Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
5bc8d83
rectify: required-join backend admission truthful
Trecek Aug 15, 2026
8ebe7e5
rectify: bind join policy to session and enforce Claude dispatch boun…
Trecek Aug 15, 2026
483c25f
rectify: declare_join_batch tool, FREE_RANGE, and shared join ledger
Trecek Aug 15, 2026
30332f2
rectify: register join claim/settle/Stop guards
Trecek Aug 15, 2026
45b79d5
rectify: declare_join_batch MCP handler
Trecek Aug 15, 2026
613b4d7
rectify: add force-inactive agent-teams config and env neutralization
Trecek Aug 15, 2026
f49d682
rectify: migrate 45 prose-only join consumers to semantic_requirements
Trecek Aug 15, 2026
43a12a2
rectify: allow matcherless Stop hooks and update doc counts
Trecek Aug 15, 2026
34f8cbc
rectify: update test counts and singleton allow-list for join ledger
Trecek Aug 15, 2026
fb8ba54
rectify: address audit remediation — manifest-resolved session bindin…
Trecek Aug 15, 2026
f736e2b
rectify: bounded telemetry on join gates, parsed-behavior inventory test
Trecek Aug 15, 2026
ac27759
rectify: update Protocol declarations for force_inactive_agent_teams
Trecek Aug 16, 2026
df98a88
rectify: Step 1+2 conformance tests, force-inactive, settings neutral…
Trecek Aug 16, 2026
d16f164
rectify: address audit remediation — join-bearing JSON envelope, join…
Trecek Aug 16, 2026
afc0c40
rectify: fix inherited audit regressions — field-count tests, fcntl a…
Trecek Aug 16, 2026
2e71dd0
rectify: address audit Round 2 — hooks.json regeneration, pre-spawn c…
Trecek Aug 16, 2026
fe7f493
rectify: address audit Round 3 — project_root threading, OSError tran…
Trecek Aug 16, 2026
bc6c649
resolve-review: make join guards fail-closed on missing session_id
Trecek Aug 17, 2026
8a57636
resolve-review: fail-closed on malformed settings files; lift inline …
Trecek Aug 17, 2026
4a9ff14
resolve-review: clarify background_exec_guard docstring for binding-u…
Trecek Aug 17, 2026
2eaeaf3
resolve-review: strengthen hook test assertions to actually exercise …
Trecek Aug 17, 2026
127d1fb
resolve-review: drop unused errno re-export, dead fd variable, redund…
Trecek Aug 17, 2026
46e29c3
resolve-review-validate: F1 apply reviewer-recommended improvement
Trecek Aug 17, 2026
f04770c
resolve-review: address 9 critical findings from PR #4613 iteration 1
Trecek Aug 17, 2026
0c2224e
resolve-review: address warning-level findings from PR #4613 iteration 1
Trecek Aug 17, 2026
c2842b6
resolve-review: address info-level findings from PR #4613 iteration 1
Trecek Aug 17, 2026
fc08e3c
resolve-review: thread project_root through _interactive_stripped helper
Trecek Aug 17, 2026
9a5c74b
resolve-review: drop redundant inline ClaudeCodeBackend import
Trecek Aug 17, 2026
4ce6541
resolve-review: harden the new fail-closed invariants with regression…
Trecek Aug 17, 2026
fee5a5c
resolve-review: drop backward-compat narration from docstrings
Trecek Aug 17, 2026
34d3081
resolve-review: consolidate session binding reader into _hook_settings
Trecek Aug 17, 2026
656bc22
resolve-review: rewrite vacuous assertions to exercise the production…
Trecek Aug 17, 2026
bb65aa0
resolve-review: extract resolve_flag_dir helper for join ledger path
Trecek Aug 17, 2026
24fe6dc
resolve-review: drop dead os.environ mutation and raw_stdin parameter…
Trecek Aug 17, 2026
ca76255
resolve-review: drop dead test helpers, misleading comments, and floa…
Trecek Aug 17, 2026
d43a7c9
resolve-review: tighten vacuous-or assertions and outdated docstrings
Trecek Aug 17, 2026
510222a
resolve-review: type-guard env var, drop duplicate codex test
Trecek Aug 17, 2026
feeb67c
resolve-review: keep 'not valid' substring in corruption assertion
Trecek Aug 17, 2026
bbe0eb6
resolve-review: address validation gaps — finish cohesion dedup, type…
Trecek Aug 17, 2026
37e55d2
resolve-review: align declare_join_batch ledger dir with shared resolver
Trecek Aug 17, 2026
4eef3d4
resolve-review: harden join guards against non-object payload, drop d…
Trecek Aug 17, 2026
a4ee0f6
resolve-review: extend non-dict guard to settle guard main()
Trecek Aug 17, 2026
186338d
resolve-review: drop dead assignments_argument / fail_unsupported_joi…
Trecek Aug 17, 2026
3b9677a
fix: update doc counts from 75 to 76 MCP tools after rebase onto develop
Trecek Aug 17, 2026
e0d8126
fix: declare_join_batch tag, codex role_mapping, skill join inventory…
Trecek Aug 17, 2026
e0cf116
fix: codex refuses join-bearing skills at adapt-time; align tests wit…
Trecek Aug 17, 2026
aedad06
fix: exempt join-ledger + headless_helpers + bumped extensions from l…
Trecek Aug 17, 2026
9eb95b4
fix: arch tests + status_summaries error recovery
Trecek Aug 17, 2026
e37d789
fix: align test expectations with new codex refuse-join contract and …
Trecek Aug 17, 2026
0963b2a
chore: re-run CI on latest HEAD
Trecek Aug 17, 2026
d629a75
fix: ruff auto-fix import order in claude.py and tools_kitchen.py
Trecek Aug 17, 2026
3c58f41
fix: ruff format apply to 8 markdown files
Trecek Aug 17, 2026
9c3ecfc
fix: resolve pre-commit violations
Trecek Aug 17, 2026
91dd381
fix: correct doc-counts to match actual source (75 tools, 141 skills)
Trecek Aug 17, 2026
c4c661e
fix: revert import/schema regressions, fix false-positive join declar…
Trecek Aug 17, 2026
968e770
fix: exclude join-refused skills at every catalog/projection admissio…
Trecek Aug 17, 2026
4ca854c
fix: two remaining CI failures missed in earlier batches
Trecek Aug 17, 2026
9b05631
fix: revert incorrect readOnlyHint flip, fix the actual stale test al…
Trecek Aug 17, 2026
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
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

AutoSkillit is a Claude Code plugin that runs YAML recipes through a
multi-level orchestrator. The bundled recipes implement issue → plan → worktree
→ tests → PR → merge pipelines using 74 MCP tools and 141 bundled skills.
→ tests → PR → merge pipelines using 75 MCP tools and 141 bundled skills.

## Start here

Expand Down
2 changes: 1 addition & 1 deletion docs/execution/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ merge gates.
- [claude-startup-readiness.md](claude-startup-readiness.md) — bounded MCP addressability and conformance evidence
- [explorer-agents.md](explorer-agents.md) — bounded specialized repository exploration agents
- [fleet-effect-provenance.md](fleet-effect-provenance.md) — dispatch effect receipts and retry disposition
- [tool-access.md](tool-access.md) — visibility and authority across all 74 MCP tools
- [tool-access.md](tool-access.md) — visibility and authority across all 75 MCP tools
- [orchestration.md](orchestration.md) — orchestration levels, retry reasons, merge decision tree
- [orchestration-levels.md](../orchestration-levels.md) — L0–L3 level definitions, mapping table
27 changes: 22 additions & 5 deletions docs/execution/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ How AutoSkillit runs a recipe end to end: orchestrator, kitchen gating, clone an

## Overview

AutoSkillit is a Claude Code plugin that orchestrates automated workflows using headless sessions. It provides 74 MCP tools and 141 bundled skills, organized into a gated visibility system.
AutoSkillit is a Claude Code plugin that orchestrates automated workflows using headless sessions. It provides 75 MCP tools and 141 bundled skills, organized into a gated visibility system.

## Core Concepts

Expand Down Expand Up @@ -39,8 +39,8 @@ AutoSkillit uses several overlapping tool visibility surfaces:
`mcp.enable({'headless'})` — `test_check`, `unlock_agent_pack`, `commit_files`,
`write_audit_semantic_result`, `write_standalone_audit_evidence`,
`write_audit_disposition_bundle`, `post_pr_review`, and `delegate_evidence_reader`.
- **Kitchen-tagged tools (51 tools total)**: Gated behind `open_kitchen` — `run_skill`,
`run_cmd`, `run_python`, `merge_worktree`, `clone_repo`, `push_to_remote`, and 45 more.
- **Kitchen-tagged tools (52 tools total)**: Gated behind `open_kitchen` — `run_skill`,
`run_cmd`, `run_python`, `merge_worktree`, `clone_repo`, `push_to_remote`, and 46 more.
Seven kitchen tools also carry the `headless` tag and are
additionally pre-enabled in headless sessions. `post_pr_review` is headless-only and
deliberately not application-gated.
Expand Down Expand Up @@ -102,15 +102,15 @@ AutoSkillit supports four session modes with different tool and skill visibility

- **`$ claude` (plugin, no kitchen)**: Regular Claude Code session with the AutoSkillit plugin
loaded. Sees the 8 Free Range MCP tools and Tier 1 skills only
(`open-kitchen`, `close-kitchen`). After calling `/open-kitchen`, all 51 kitchen-tagged MCP
(`open-kitchen`, `close-kitchen`). After calling `/open-kitchen`, all 52 kitchen-tagged MCP
tools become available.

- **`$ autoskillit cook`**: Interactive development session. Sees all three skill tiers
(Tier 1+2+3) via an ephemeral session directory. MCP tools are initially ungated (same as
`$ claude`); `/open-kitchen` reveals kitchen tools.

- **`$ autoskillit order`**: Pipeline orchestrator session. Kitchen is pre-opened at startup.
The authenticated evidence-reader brokers remain hidden among the 74 registered MCP tools
The authenticated evidence-reader brokers remain hidden among the 76 registered MCP tools
because only a separately launched reader child receives their binding. All skill tiers are
accessible. The orchestrator delegates work through `run_skill` (headless sessions) and
`run_cmd` (shell commands).
Expand All @@ -123,6 +123,23 @@ AutoSkillit supports four session modes with different tool and skill visibility
This prevents recursive session nesting and keeps the orchestrator as a pure routing engine.
See **[Skill Visibility](../skills/visibility.md)** for the full tier breakdown and configuration.

## Join Contract and Batch Admission

A skill that declares `semantic_requirements.join.required: true` enters a join-bound session the moment Claude loads it. The hook layer carries the join policy and the batch ledger:

1. **`declare_join_batch`** opens one parent/wave with resolved assignment labels, validates the loaded skill's `join.required` and `child_spawn_cardinality` against the projection manifest, and returns a fresh `join_batch_id`.
2. **JoinLedger** keys membership and outcomes by `(session_id, top_level_parent, join_batch_id, assignment, tool_use_id)`. Persistence uses `fcntl.flock` + atomic `os.replace` (`hooks/_join_ledger.py`).
3. **Claim → Settle → Stop lifecycle** —
* `join_claim_guard` (PreToolUse, matcher `Agent`) atomically claims one declared assignment per top-level direct `Agent` `tool_use_id`.
* `join_settle_guard` (PostToolUse + PostToolUseFailure) maps the upstream event to one of `success / failure / timeout / cancelled / interruption / missing` and records the outcome on the claimed handle. Empty results are mapped to `missing`, never `success`.
* `join_followup_guard` (matcherless PreToolUse) denies non-`Agent` side-effecting calls while a wave is unresolved.
* `join_stop_guard` (Stop, exit code 2) blocks Claude from completing until the wave is `complete`.
4. **Backend admission** — `BackendCapabilities.fixed_set_join_capable` is statically `True` only for Claude Code, and only when the full guard set is registered in the same commit. Codex returns `unsupported_operation(REQUIRED_JOIN)` at admission; current Codex has wait-any/mailbox semantics, not fixed-set fan-in.
5. **Session binding monotonicity** — `skill_load_post_hook.py` writes a JSON envelope with OR-accumulated `join_required`. A later join-false Skill load does not downgrade an established binding. A missing or unreadable projection manifest fails closed by forcing `join_required: true` so dispatch guards refuse all join-bearing work.
6. **Repository force-inactive option** — `agent_backend.force_claude_agent_teams_inactive` (default False) neutralizes `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` and detects conflicting entries in the target repository's `.claude/settings.json` / `.claude/settings.local.json`. Repositories with the option disabled remain byte-for-byte unchanged.

The session flag carries join policy; the manifest carries projection identity; the ledger carries wave state. Each is read by the matching hook family. None of them is a duplicate authority — they are three projections of one decision.

## Durable Codex Cook Sessions

Codex cook history uses a per-attempt view rather than exposing the complete
Expand Down
9 changes: 5 additions & 4 deletions docs/execution/tool-access.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# MCP Tool Access Control

AutoSkillit provides 74 MCP tools across overlapping visibility surfaces that control which
AutoSkillit provides 75 MCP tools across overlapping visibility surfaces that control which
session types can see each tool. Visibility determines addressability; each tool still enforces
its own authority contract.

Expand Down Expand Up @@ -140,7 +140,7 @@ missing kitchen visibility.

## Complete MCP Tool Access Control Map

All 74 tools with their access level, tags, source file, and functional category.
All 75 tools with their access level, tags, source file, and functional category.

**Tag abbreviations**: AS = `autoskillit`, K = `kitchen`, HL = `headless`,
ER = `evidence-reader`, GH = `github`, CI = `ci`, CL = `clone`,
Expand All @@ -159,7 +159,8 @@ TL = `telemetry`, FL = `fleet`
| `reload_session` | AS | `server/tools_kitchen.py` |
| `configure_fleet` | AS | `server/tools_config.py` |
| `configure_order` | AS | `server/tools_config.py` |
| `lock_ingredients` | AS | `server/tools_config.py` |
| `lock_ingredients` | AS | `server/tools_kitchen.py` |
| `declare_join_batch` | AS, K | `server/tools_kitchen.py` | Opens one declared-batch JoinLedger for the next wave; see `JoinLedger` lifecycle. Claude-only when `fixed_set_join_capable`. |

---

Expand Down Expand Up @@ -299,7 +300,7 @@ dynamically gated until opening completes. The bounded client snapshot and
fresh/resume behavior are documented in
[Claude startup readiness](claude-startup-readiness.md).

**Total: 74 registered tools**. The 51 kitchen-tagged tools include seven of the eight
**Total: 75 registered tools**. The 51 kitchen-tagged tools include seven of the eight
headless tools. The two authenticated evidence-reader brokers are excluded from the
kitchen, free-range, and fleet counts.

Expand Down
60 changes: 60 additions & 0 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,63 @@ Open an issue in the GitHub repository. AutoSkillit also has a built-in
`report_bug` MCP tool that the `pipeline-summary` skill calls automatically
when an overnight pipeline surfaces a bug. The tool deduplicates against
existing open issues by fingerprint.

### Does AutoSkillit force Claude agent teams off?

No, not by default. The `agent_backend.force_claude_agent_teams_inactive`
configuration option defaults to **false**, scoped per-repository (project
configuration overrides user-level `.claude/settings.json`). When the
operator sets it to **true** on a target repo, AutoSkillit strips
`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` from the launch environment before
every Claude launch (interactive, resume, skill-session, and food-truck
builders) and rewrites any conflicting `env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`
entry in the target repo's `.claude/settings.json` or `.claude/settings.local.json`.
The pre-spawn checkpoint fail-closes: when the effective environment still
carries a truthy team value, the launch refuses with an explicit reason.

### When do teams help, and when is the join contract required?

The force-inactive policy is **not** a global rule — it exists because
join-bearing skills need an unguarded, declared-batch surface that
team-mode routing defeats. Legitimate team workflows (named teammate
dispatch, team-name routing, background tasks) continue to work in any
session that has not loaded a join-bearing skill. A session that loads a
join-bearing skill is permanently bound for the rest of its lifetime: a
later load of a non-join skill cannot downgrade the binding. To re-enable
team workflows in a session, the operator must start a fresh session after
the join-bearing load.

### Can Codex run join-bearing skills?

Not today. Codex's static capability attestation reports
`fixed_set_join_capable=False`. When a skill declares
`semantic_requirements.join.required: true`, the `declare_join_batch` MCP
tool refuses with `unsupported_operation(REQUIRED_JOIN)` and the skill
cannot be admitted. Codex support requires the harness to expose a
fixed-set fan-in primitive; until then, the backend gate is the single
honest source.

### What happens when I try a named Claude dispatch in a join-bound session?

It is denied before child creation. The `background_exec_guard`
PreToolUse hook reads the session binding and rejects any Agent call with
`name`, `team_name`, or `run_in_background` selectors while
`join_required=true`. The denial names the rejected selectors and points
the operator at the `declare_join_batch` gateway — declare a wave with
resolved assignment labels and re-dispatch as ordinary unnamed foreground
Agent calls. The `ScheduleWakeup` deferral hook is denied for the same
reason: deferral cannot produce the declared-batch evidence the join
contract requires.

### What's the difference between `join_required` and `team_name`?

`join_required` is the semantic authority over the **parent's** dispatch
boundary: a parent that loads a join-bearing skill must use the
declared-batch fan-in path; the join contract gates its child routing.
`team_name` is a Claude-only runtime selector that names a teammate under
agent teams. They are not interchangeable: a join-bearing parent cannot
dispatch via `team_name` (the dispatch guard denies it), and a non-join
parent that names a teammate under agent teams is not bound by the join
contract at all — it is the legitimate team workflow path described
above. The two surfaces never overlap in the same session.

8 changes: 4 additions & 4 deletions docs/safety/hooks.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# Hooks

AutoSkillit registers 46 Claude Code hook scripts: 35 PreToolUse, 9 PostToolUse,
and 2 SessionStart. Every script is stdlib-only Python so it can run before the
AutoSkillit registers 51 Claude Code hook scripts: 37 PreToolUse, 11 PostToolUse,
2 SessionStart, and 1 Stop. Every script is stdlib-only Python so it can run before the
project virtualenv is on the path. Scripts live in `src/autoskillit/hooks/`
and are bound to event types in `src/autoskillit/hook_registry.py` via the
`HOOK_REGISTRY` list of `HookDef` entries; `generate_hooks_json()` then
materializes the canonical `hooks.json` that Claude Code reads.

## PreToolUse hooks (35)
## PreToolUse hooks (37)

### `branch_protection_guard.py`
**Guarded tools:** `merge_worktree`, `push_to_remote`
Expand Down Expand Up @@ -413,7 +413,7 @@ closed when their identity is malformed or the record cannot be written, while
malformed JSON and unrelated tools remain fail-open. Codex and headless terminal
authority do not use this bridge.

## PostToolUse hooks (9)
## PostToolUse hooks (10)

### `pretty_output_hook.py`
**Guarded tools:** all AutoSkillit MCP tools
Expand Down
5 changes: 4 additions & 1 deletion scripts/check_tool_annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
from pathlib import Path

TOOLS_DIR = Path(__file__).resolve().parent.parent / "src" / "autoskillit" / "server" / "tools"
READ_ONLY_EXCEPTIONS = {"open_kitchen": False}
# REQ-ARCH-ANNOTATION-E1: open_kitchen and declare_join_batch are the only
# effectful tools; the former opens the kitchen session and the latter opens
# a join batch ledger entry. Every other tool must remain readOnlyHint=True.
READ_ONLY_EXCEPTIONS = {"open_kitchen": False, "declare_join_batch": False}


def check() -> list[str]:
Expand Down
13 changes: 9 additions & 4 deletions src/autoskillit/agents/plan-registry-tracer.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ LSP tracks typed references but misses field names embedded as **string literals
`tree-sitter-python` (v0.25) and `tree-sitter-language-pack` are installed as project dev dependencies. Run via `python3` in Bash. Example — find a field name inside registry dicts/frozensets:

```python
python3 << 'PYEOF'
python3 << "PYEOF"
import tree_sitter_python as tspython
from tree_sitter import Language, Parser
from pathlib import Path
Expand All @@ -58,25 +58,30 @@ import os
FIELD = "TARGET_FIELD_NAME" # replace with actual field
parser = Parser(Language(tspython.language()))


def find_in_file(fpath):
source = fpath.read_bytes()
tree = parser.parse(source)
hits = []

def walk(node):
if node.type == "string":
text = node.text.decode().strip('"').strip("'")
if FIELD in text:
ctx = node.parent.type if node.parent else "?"
hits.append((node.start_point[0]+1, text, ctx))
hits.append((node.start_point[0] + 1, text, ctx))
if node.type == "keyword_argument":
name = node.child_by_field_name("name")
if name and FIELD in name.text.decode():
hits.append((node.start_point[0]+1, name.text.decode(), "keyword_argument"))
for c in node.children: walk(c)
hits.append((node.start_point[0] + 1, name.text.decode(), "keyword_argument"))
for c in node.children:
walk(c)

walk(tree.root_node)
for line, text, ctx in hits:
print(f" {fpath}:{line} — '{text}' (inside {ctx})")


root = os.environ.get("CODEBASE_ROOT", ".")
for f in Path(root, "src").rglob("*.py"):
find_in_file(f)
Expand Down
2 changes: 2 additions & 0 deletions src/autoskillit/cli/session/_session_launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def prepare_interactive_launch(
tools: Sequence[str] = (),
add_dirs: Sequence[Path | str | ValidatedAddDir] = (),
generated_home: Path | None = None,
force_inactive_agent_teams: bool = False,
) -> PreparedInteractiveLaunch:
"""Probe an exact executable before sealing the capability-complete session env."""

Expand Down Expand Up @@ -122,6 +123,7 @@ def prepare_interactive_launch(
add_dirs=add_dirs,
generated_home=generated_home,
tools=tools,
force_inactive_agent_teams=force_inactive_agent_teams,
)
final = resolve_executable_launch_binding(
binary_name=backend.binary_name(),
Expand Down
6 changes: 6 additions & 0 deletions src/autoskillit/config/_config_dataclasses.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,12 @@ class AgentBackendConfig:
backend: str = "claude-code"
step_overrides: dict[str, str] = field(default_factory=dict)
recipe_overrides: dict[str, dict[str, str]] = field(default_factory=dict)
# Repository-scoped toggle: when True, the Claude launcher neutralizes
# CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS in both the process env and the
# target repository's .claude/settings*.json files before spawn. Defaults
# to False — repositories with the option disabled remain byte-for-byte
# unchanged. Independent from join.required. Refs #4575.
force_claude_agent_teams_inactive: bool = False

def __post_init__(self) -> None:
if not self.backend:
Expand Down
1 change: 1 addition & 0 deletions src/autoskillit/config/ingredient_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
"configure_fleet",
"configure_order",
"lock_ingredients",
"declare_join_batch",
),
),
)
Expand Down
7 changes: 7 additions & 0 deletions src/autoskillit/core/tool_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"configure_order",
"create_and_publish_branch",
"create_unique_branch",
"declare_join_batch",
"disable_quota_guard",
"dispatch_food_truck",
"enable_exploration",
Expand Down Expand Up @@ -678,6 +679,12 @@ def _run_skill() -> ToolDef:
roles={"_autoskillit_exploration_request_token": ToolParamRole.ORCHESTRATOR_SCOPING},
),
_tool("lock_ingredients", ("locked", "pipeline_id", "unlock")),
_tool(
"declare_join_batch",
("skill_name", "assignments", "session_id", "top_level_parent"),
required=("skill_name", "assignments", "session_id"),
wire_types={"assignments": ToolWireType.ARRAY},
),
_tool("reload_session"),
_tool("record_pipeline_step", ("pipeline_id", "op", "dependencies", "step_name")),
_tool("get_pr_reviews", ("pr_number", "cwd", "repo"), required=("pr_number", "cwd")),
Expand Down
12 changes: 12 additions & 0 deletions src/autoskillit/core/types/_type_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,16 @@ class BackendCapabilities:
# Interactive hook trust behavior. Automated builders retain their explicit
# bypass policy; interactive launchers translate this policy into CLI flags.
hook_trust_policy: HookTrustPolicy = HookTrustPolicy.AUTOMATED
# True only when the backend natively provides fixed-set join semantics:
# a declared batch declaration tool, an Agent PreToolUse claim guard,
# PostToolUse and PostToolUseFailure settlers, an unresolved-follow-up
# gate, and a Stop completion gate are all installed and capability-attested.
# This is a static declaration that must be paired with unconditional
# registration of every required hook in HOOK_REGISTRY in the same commit.
# Codex does NOT satisfy this contract — its wait-any/mailbox semantics
# cannot realize exact-set fixed membership, so its `fixed_set_join_capable`
# must remain False until the active harness exposes a real fixed-set primitive.
fixed_set_join_capable: bool = False


ALL_PROJECT_LOCAL_SKILL_SEARCH_DIRS: tuple[str, ...] = (
Expand Down Expand Up @@ -406,6 +416,7 @@ def model_class(model: str) -> str:
protected_recipe_delivery_capable=False,
recipe_delivery_budget=None,
hook_trust_policy=HookTrustPolicy.AUTOMATED,
fixed_set_join_capable=True,
)


Expand Down Expand Up @@ -498,6 +509,7 @@ class SkillSessionConfig:
native_shell_capture_decision: NativeShellCaptureDecision | None = None
managed_lineage_ref: ManagedHeadlessSessionLineageRef | None = None
managed_attempt_id: str | None = None
force_inactive_agent_teams: bool = False

def __post_init__(self) -> None:
managed_values = (
Expand Down
1 change: 1 addition & 0 deletions src/autoskillit/core/types/_type_constants_registries.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@
"configure_fleet",
"configure_order",
"lock_ingredients", # NEW (#3357)
"declare_join_batch", # NEW (REQ-JOIN-001 — REQ-JOIN-002, #4575)
}
)

Expand Down
Loading
Loading