Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ This index covers the current product guides, developer references, and dated en
- [V3 SQLite migration plan](superpowers/plans/2026-10-14-v3-issue-264.md) records ordered schema migrations, backups, persisted approval history, and verification for issue #264.
- [V3 Working Plan contract](superpowers/plans/2026-10-14-v3-issue-241.md) records plan ownership, complexity policy, lifecycle, persistence, and verification for issue #241.
- [V3 atomic Working Plan edits](superpowers/plans/2026-10-16-v3-issue-242.md) records revision-checked operations, atomic persistence, ordering, dependencies, and validation for issue #242.
- [V3 Strategic Plan contract](superpowers/plans/2026-10-16-v3-issue-245.md) records approval versions, execution bounds, task links, and acceptance evidence for issue #245.
- [V3 plan index](superpowers/plans/index.md) links the issue-specific implementation plans and identifies their coverage.
- [V3 execution receipt implementation plan](superpowers/plans/2026-10-14-v3-issue-236.md) records receipt identity, explicit task binding, structured effect verification, compatibility, and validation for issue #236.
- [V3 runtime events implementation plan](superpowers/plans/2026-10-14-v3-issue-255.md) records the canonical event contract, correlation, interface adapters, and validation for issue #255.
Expand Down
167 changes: 167 additions & 0 deletions docs/superpowers/plans/2026-10-16-v3-issue-245.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/superpowers/plans/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [V3 #264 — Version SQLite state and migrate safely](2026-10-14-v3-issue-264.md)
- [V3 #241 — Working Plans and task lifecycle](2026-10-14-v3-issue-241.md)
- [V3 #242 — Atomic Working Plan edits](2026-10-16-v3-issue-242.md)
- [V3 #245 — Versioned, user-approved Strategic Plans](2026-10-16-v3-issue-245.md)
- [V3 #236 — Execution receipts and task association](2026-10-14-v3-issue-236.md)
- [V3 #255 — Shared typed runtime events](2026-10-14-v3-issue-255.md)

Expand Down
2 changes: 2 additions & 0 deletions docs/tasks-and-automation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Task IDs and records are actor/workspace/session scoped. The web task API expose

Simple work does not require a plan, and a plan is optional for medium work. Complex direct work uses a durable Working Plan with runtime-owned stable IDs and explicit acceptance criteria. The typed `update_plan` boundary applies revision-checked batches of add, update, cancel, reorder, and dependency operations; legacy `complexity`/`tasks` input is adapted through the same validation path. A changed task must still be pending and unexecuted; executed task records and evidence are preserved, and changed work is represented by a new task after cancellation. Scheduling follows plan order and waits for every dependency to succeed. A plan completes only when every task succeeds with acceptance evidence; recovery also reconciles a crash between the final task write and the plan status write. Clearing an active plan cancels its unfinished steps. The existing foreground text protocol continues to use Plan/TaskList compatibility until the native foreground loop is migrated.

Plan Mode can produce a versioned Strategic Plan before execution. Acceptance records the exact objectives, acceptance criteria, workspace paths, capabilities, effect categories, and risk ceiling alongside its linked Working Plan. A step may also carry a visible, fingerprinted `execution` contract for one exact `write_file` or `edit_file` call; delegated file mutations require this explicit contract and still pass assigned-file, workspace-bound, and tool-approval checks. Each criterion should include a `verification` action and exact object arguments. A `read_file` verifier must also include one case-sensitive `expect` predicate (`equals` or nonempty `contains`); the returned text must satisfy it before the criterion is recorded. Plain-text criteria remain readable for legacy proposals but cannot satisfy the per-criterion completion gate without a verifier. Runtime tool dispatch checks each tool's catalog policy and supplied paths against those accepted bounds; shell processes are denied because this runtime cannot confine arbitrary commands to those paths. An unbounded legacy proposal receives read-only defaults. Strategic acceptance does not grant capabilities, bypass tool approvals, or establish completion evidence.

For a typed plan step, include an optional `execution` object with the canonical tool `action` and object `arguments`. Native tool calls associate with a task only when the runtime receives that task's explicit ID; matching action and arguments alone never select a task. A successful associated receipt may add execution evidence, but it cannot satisfy acceptance criteria by itself. A delegated assignment may carry that explicit Working Plan task ID; the parent records task evidence only after the independent review succeeds. The legacy text adapter retains its bounded matching behavior for compatibility. Plan IDs and task IDs are returned as structured result data so later updates can retain runtime-owned task identities.

## Sub-agents
Expand Down
26 changes: 21 additions & 5 deletions openkyrozen/agent/delegation_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -361,11 +361,27 @@ def _delegation_tool_access(self, action, args):
if path not in owned:
raise ValueError("Sub-agent write is outside its assigned files")
parent = getattr(self.current_session, "_delegation_parent", None)
if parent and parent.interaction.state().get("executing_plan") and self._is_state_changing_action(action, args):
structured = json.dumps(args, ensure_ascii=False, sort_keys=True) if isinstance(args, dict) else str(args)
allowed, reason = parent.tasks.mutation_matches_current_task(action, structured)
if not allowed:
raise ValueError("Sub-agent action does not match accepted plan: " + reason)
parent_plan = parent.interaction.state().get("executing_plan") if parent else None
if parent and parent_plan:
from openkyrozen.agent.executor import _legacy_object_arguments, _strategic_plan_denial
arguments = args if isinstance(args, dict) else None
spec = getattr(self.tool_registry, "specs", {}).get(action)
if arguments is None and isinstance(args, str):
if spec is not None:
normalized = _legacy_object_arguments(args, spec)
arguments = normalized if normalized else None
match_args = (json.dumps(arguments, ensure_ascii=False, sort_keys=True, separators=(",", ":"))
if arguments is not None else str(args))
denial = _strategic_plan_denial(
parent_plan, action, arguments if arguments is not None else args,
spec, parent.workspace.root,
)
if denial:
raise PermissionError(f"Sub-agent operation exceeds the accepted Strategic Plan: {denial}")
if self._is_state_changing_action(action, args):
allowed, reason = parent.tasks.mutation_matches_current_task(action, match_args)
if not allowed:
raise ValueError("Sub-agent action does not match accepted plan: " + reason)
guarded = action in {"read_file", "write_file", "edit_file", "search_files"} or self._is_state_changing_action(action, args) or action in {"git_diff", "git_show"}
if access and guarded:
cancelled = (lambda: coordinator.cancelled[context.child_run_id].is_set()) if coordinator else (lambda: False)
Expand Down
Loading
Loading