Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e55a089
Rectify delivery-bound summary self-starvation (Part A)
Trecek Jul 21, 2026
7195c78
test: add regression test for ctx is None fail-open gap (Part A remed…
claude Jul 21, 2026
9fc93ad
fix: remove backend_inspected gate in track_response_size (Part A rem…
claude Jul 21, 2026
c32fd54
test: parametrize starvation tests over post_prune_step_names contras…
claude Jul 21, 2026
5313ef3
fix: stabilize open_kitchen tests against track_response_size worst-c…
Trecek Jul 21, 2026
5d212e4
feat: bounded envelope + pull architecture for recipe delivery (Part B)
Trecek Jul 21, 2026
94a2221
fix: include bounded recipe pull tool in gate expectations
Trecek Jul 21, 2026
343d5a6
fix: unconditional artifact backstop persistence + drop diagram forwa…
Trecek Jul 21, 2026
721250c
feat: wire open_kitchen to the bounded envelope + pull architecture
Trecek Jul 21, 2026
39a2e69
test: update tests broken by the open_kitchen envelope shape
Trecek Jul 21, 2026
52f142c
test: add TDD coverage for the bounded envelope + pull architecture
Trecek Jul 21, 2026
f8331b3
fix: regressions surfaced by wiring open_kitchen into the envelope ar…
Trecek Jul 21, 2026
550ad2f
fix: degrade advisory envelope fields on delivery-bound overflow
Trecek Jul 21, 2026
8d791af
test: assert Part B envelope keys survive delivery-bound projection
Trecek Jul 21, 2026
03871ef
fix: give the delivery-bound Part B artifact_path sentinel a real bac…
Trecek Jul 21, 2026
8c00afa
fix(review): paginate list-typed sections by element, not JSON-string…
Trecek Jul 22, 2026
83b3c82
fix(review): consolidate duplicated envelope delivery-bound resolver
Trecek Jul 22, 2026
e31219e
fix(review): do not advertise steps as pullable when ingredients_only…
Trecek Jul 22, 2026
32f36be
fix(review): give _bounded_append's internal invariant its own except…
Trecek Jul 22, 2026
b404c85
test(review): rename doc-count tests to match their asserted values
Trecek Jul 22, 2026
e7ab996
fix(review): re-pin pyright suppression allowlist line after import a…
Trecek Jul 22, 2026
d72f7ee
fix(review): splice incoming items into candidates when merging past …
Trecek Jul 22, 2026
477d24d
fix(review): record ingredients_only in recipe_artifact_state so recr…
Trecek Jul 22, 2026
ec6111e
fix(review): consolidate duplicated delivery-bound fallback resolution
Trecek Jul 22, 2026
46c4740
fix(review): restore orchestration_rules/stop_step_semantics falsy as…
Trecek Jul 22, 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 59 MCP tools and 142 bundled skills.
→ tests → PR → merge pipelines using 60 MCP tools and 142 bundled skills.

## Start here

Expand Down
4 changes: 2 additions & 2 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 59 MCP tools and 142 bundled skills, organized into a gated visibility system.
AutoSkillit is a Claude Code plugin that orchestrates automated workflows using headless sessions. It provides 60 MCP tools and 142 bundled skills, organized into a gated visibility system.

## Core Concepts

Expand Down Expand Up @@ -68,7 +68,7 @@ AutoSkillit supports four session modes with different tool and skill visibility
`$ claude`); `/open-kitchen` reveals kitchen tools.

- **`$ autoskillit order`**: Pipeline orchestrator session. Kitchen is pre-opened at startup —
all 59 MCP tools are available immediately. All skill tiers are accessible. The orchestrator
all 60 MCP tools are available immediately. All skill tiers are accessible. The orchestrator
delegates work through `run_skill` (headless sessions) and `run_cmd` (shell commands).

- **`run_skill` (headless)**: Worker sessions launched by the orchestrator. Sees 4 Free Range
Expand Down
4 changes: 2 additions & 2 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 59 MCP tools organized into three access levels that control which
AutoSkillit provides 60 MCP tools organized into three access levels that control which
session types can see each tool.

## Three Access Levels
Expand Down Expand Up @@ -86,7 +86,7 @@ missing kitchen visibility.

## Complete MCP Tool Access Control Map

All 59 tools with their access level, tags, source file, and functional category.
All 60 tools with their access level, tags, source file, and functional category.

**Tag abbreviations**: AS = `autoskillit`, K = `kitchen`, HL = `headless`,
GH = `github`, CI = `ci`, CL = `clone`, TL = `telemetry`, FL = `fleet`
Expand Down
2 changes: 1 addition & 1 deletion docs/skills/visibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ and `/autoskillit:close-kitchen`. Skills in `skills_extended/` are never seen.

Order is similar to cook: AutoSkillit launches Claude Code with access to all tiers.
The key difference is the orchestrator (`sous-chef` skill) is injected and the kitchen
is pre-opened so all 59 MCP tools are available from the start.
is pre-opened so all 60 MCP tools are available from the start.

### Headless session (launched by `run_skill`)

Expand Down
11 changes: 10 additions & 1 deletion src/autoskillit/config/ingredient_defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,16 @@
"commit_files",
),
),
("Recipes", ("migrate_recipe", "list_recipes", "load_recipe", "validate_recipe")),
(
"Recipes",
(
"migrate_recipe",
"list_recipes",
"load_recipe",
"validate_recipe",
"get_recipe_section",
),
),
("Agents", ("unlock_agent_pack",)),
(
"Clone & Remote",
Expand Down
1 change: 1 addition & 0 deletions src/autoskillit/core/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,7 @@ from .types import TimingLog as TimingLog
from .types import TokenFactory as TokenFactory
from .types import TokenLog as TokenLog
from .types import TraditionManifest as TraditionManifest
from .types import TruncationBoundsError as TruncationBoundsError
from .types import ValidatedAddDir as ValidatedAddDir
from .types import ValidatedWorktreePath as ValidatedWorktreePath
from .types import WorkspaceManager as WorkspaceManager
Expand Down
6 changes: 6 additions & 0 deletions src/autoskillit/core/types/_type_constants_registries.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
"create_and_publish_branch",
"record_pipeline_step",
"reset_dispatch",
"get_recipe_section", # Part B Step 2.3 — bounded pull tool
}
)

Expand Down Expand Up @@ -176,6 +177,7 @@
"open_kitchen_deferred_recall", # S2 — deferred-recall re-serve
"load_recipe", # S3 — re-serve tool
"get_recipe", # S4 — MCP resource handler
"get_recipe_section", # S5 — bounded pull tool for step/section content
}
)

Expand Down Expand Up @@ -337,6 +339,10 @@ class AgentPackDef(NamedTuple):
"merge_worktree": frozenset({"kitchen-core"}),
"unlock_agent_pack": frozenset({"kitchen-core"}),
"record_pipeline_step": frozenset({"kitchen-core"}),
# Part B Step 2.3: get_recipe_section is a kitchen-core-tagged tool.
# It pulls recipe content on demand; food trucks don't need it (they
# receive the full recipe via dispatch) so no fleet tag is required.
"get_recipe_section": frozenset({"kitchen-core"}),
}

ALL_VISIBILITY_TAGS: frozenset[str] = frozenset(
Expand Down
11 changes: 11 additions & 0 deletions src/autoskillit/core/types/_type_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"RecipeLoadError",
"ProcessStaleError",
"RecipeNotFoundError",
"TruncationBoundsError",
]


Expand All @@ -29,3 +30,13 @@ def __init__(self, capability: str, backend_name: str) -> None:
self.capability = capability
self.backend_name = backend_name
super().__init__(f"{backend_name!r} does not support capability {capability!r}")


class TruncationBoundsError(Exception):
"""Internal sizing invariant violated: bounds too small for the truncation sentinel.

Deliberately not a ``RecipeLoadError``/``ValueError`` subclass so it is not
conflated with recipe-authoring errors by ``load_and_validate``'s
``except ValueError`` handler — it signals a misconfigured internal
constant, not a problem with the recipe being loaded.
"""
2 changes: 2 additions & 0 deletions src/autoskillit/execution/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
ensure_codex_mcp_registered,
generate_codex_hooks_config,
get_backend,
resolve_worst_case_delivery_bound,
sync_hooks_to_codex_config,
)
from autoskillit.execution.ci import DefaultCIWatcher
Expand Down Expand Up @@ -245,6 +246,7 @@
"ensure_codex_mcp_registered",
"generate_codex_hooks_config",
"sync_hooks_to_codex_config",
"resolve_worst_case_delivery_bound",
# anomaly_detection
"detect_anomalies",
"AnomalyKind",
Expand Down
18 changes: 18 additions & 0 deletions src/autoskillit/execution/backends/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,23 @@ def get_backend(name: str) -> CodingAgentBackend:
return cls()


def resolve_worst_case_delivery_bound() -> int:
"""Smallest ``effective_delivery_token_limit`` across all registered backends.

Acts as the canonical "worst-case default" used when backend capabilities
are unavailable or zero. Returns ``0`` only if every registered backend
reports zero; production callers normalize that case at the enforcement
boundary rather than here.
"""
limits: list[int] = []
for backend_cls in BACKEND_REGISTRY.values():
caps = backend_cls().capabilities
limit = getattr(caps, "effective_delivery_token_limit", 0)
if limit > 0:
limits.append(limit)
return min(limits) if limits else 0


__all__ = [
"BACKEND_REGISTRY",
"CODEX_EXEC_FLAGS",
Expand Down Expand Up @@ -95,4 +112,5 @@ def get_backend(name: str) -> CodingAgentBackend:
"ensure_codex_mcp_registered",
"get_backend",
"make_codex_scenario_player",
"resolve_worst_case_delivery_bound",
]
5 changes: 5 additions & 0 deletions src/autoskillit/hooks/formatters/_fmt_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,11 @@ def _fmt_load_recipe(data: LoadRecipeResult, pipeline: bool) -> str:
"post_prune_step_names", # internal preflight field; not displayed to agent
"dispatch_feasible", # internal admission control signal; surfaced via refusal envelopes
"infeasible_steps", # internal admission control detail; surfaced via refusal envelopes
"step_flow_skeleton", # compact envelope routing graph; dedicated formatter is Part B
"step_index", # compact envelope step identifier map; dedicated formatter is Part B
"artifact_path", # compact envelope pull-tool metadata; dedicated formatter is Part B
"sha256", # compact envelope pull-tool metadata; dedicated formatter is Part B
"pull_tool", # compact envelope pull-tool metadata; dedicated formatter is Part B
}
)

Expand Down
1 change: 1 addition & 0 deletions src/autoskillit/hooks/formatters/pretty_output_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ def _response_spill_notice(metadata: dict) -> str:
# When adding a new tool, it MUST appear either in _FORMATTERS or here.
_UNFORMATTED_TOOLS: frozenset[str] = frozenset(
{
"get_recipe_section", # recipe artifact pull envelope, generic renders correctly
"run_python", # structured result dict, generic renders correctly
"read_db", # tabular rows, generic renders correctly
"reset_test_dir", # simple ack
Expand Down
7 changes: 7 additions & 0 deletions src/autoskillit/pipeline/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ class ToolContext:
active_recipe_ingredients: frozenset[str] | None — ingredient keys declared by the loaded
recipe (frozenset() when kitchen open but no recipe loaded; None when
closed)
recipe_artifact_state: dict[str, Any] | None — server-side cache of the most recently
persisted recipe artifact (artifact_path, sha256, and the recipe-load
parameters needed to recreate it via load_and_validate). Set by
open_kitchen / load_recipe after the artifact is written; read by
get_recipe_section for sha256-verified retrieval. None when no
recipe has been loaded in this session.
temp_dir: Resolved temp directory for this project. Sentinel-guarded: raises
TypeError if not supplied explicitly. Use make_context() or pass
temp_dir=<path>.
Expand Down Expand Up @@ -181,6 +187,7 @@ class ToolContext:
active_recipe_ingredients: frozenset[str] | None = field(default_factory=lambda: None)
session_serve_overrides: ServeOverridesSnapshot | None = field(default_factory=lambda: None)
session_serve_defer_unresolved: bool = field(default=False)
recipe_artifact_state: dict[str, Any] | None = field(default_factory=lambda: None)
quota_refresh_task: QuotaRefreshTask | None = field(default=None)
token_factory: TokenFactory | None = field(default=None)
fleet_lock: FleetLock | None = field(default=None)
Expand Down
Loading