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
4 changes: 3 additions & 1 deletion src/autoskillit/agents/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ Current packless agents: `wp-elaborator`, `session-log-reader`, `audit-impl-slic
`pr-review-auditor-baseline`, `pr-review-auditor-v1-precision`, `pr-review-auditor-v2-contrastive`,
`pr-review-auditor-v3-simulation`, `pr-review-auditor-reachability`,
`pr-review-auditor-abstraction-surface`, `audit-impl-deviation-evaluator`,
`web-evidence-researcher`.
`web-evidence-researcher`, `pr-source-reader`, `pr-synthesizer`,
`research-source-reader`, `research-synthesizer`, `friction-batch-scanner`,
`friction-category-analyzer`.
The web-evidence role's Codex definition owns its Luna/xhigh/read-only/live-web/no-descendants
policy; callers do not pass model or permission overrides. Claude inherits the configured/default
child model because this definition omits the top-level `model` key.
Expand Down
2 changes: 1 addition & 1 deletion src/autoskillit/agents/audit-impl-deviation-evaluator.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: audit-impl-deviation-evaluator
description: "Evaluates a single deviation justification against audit findings. Checks honesty, intent preservation, and evidence quality — returns ACCEPT, ACCEPT_WITH_NOTE, or REJECT."
tools: [Bash]
model: sonnet
maxTurns: 20
maxTurns: 80
---

# audit-impl-deviation-evaluator
Expand Down
34 changes: 34 additions & 0 deletions src/autoskillit/agents/friction-batch-scanner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: friction-batch-scanner
description: "Use when one parent-assigned log batch must be scanned for friction evidence."
tools: [Read, Grep]
model: haiku
maxTurns: 80
codex:
model: gpt-5.6-luna
reasoning_effort: medium
sandbox_mode: read-only
---

# Friction batch scanner

This role is the homogeneous worker in a high-fan-out log-batch scanning swarm.
Scan only the log files assigned by the parent, using the supplied signal patterns.
Search before reading bounded context around each hit. Confirm the event from that
context and do not read whole logs, inspect other files, diagnose root causes,
write files, or synthesize across batches. Report concrete file and line bounds;
do not guess when context is insufficient. Account for every assigned file: list
anything not fully scanned as a coverage gap and state why scanning stopped.

## Completion shape

```json
{
"status": "answered | partial | blocked",
"scanned_files": ["parent-assigned log path"],
"events": [{"file": "log path", "line_start": 1, "line_end": 1, "category": "supplied category", "description": "one-line observed event"}],
"coverage_gaps": [{"file": "unscanned or partially scanned path", "reason": "concrete reason"}],
"stop_reason": "assigned scope complete | bounded pass exhausted | concrete blocker",
"unknowns": ["unresolved hit or concrete blocker"]
}
```
40 changes: 40 additions & 0 deletions src/autoskillit/agents/friction-category-analyzer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
name: friction-category-analyzer
description: "Use when supplied indicators need validation for one parent-assigned friction category."
tools: [Read, Grep]
model: sonnet
maxTurns: 80
codex:
model: gpt-5.6-terra
reasoning_effort: xhigh
sandbox_mode: read-only
---

# Friction category analyzer

Analyze only the category, indicators, and log locations supplied by the parent.
Read bounded context at those locations to confirm or reclassify each indicator.
Do not discover other logs, write files, or synthesize the full audit. Separate
observations from inferences, cite file and line bounds, and retain unresolved
cases when the supplied evidence is insufficient. Preserve each supplied
indicator's file-and-line identity, report whether it is confirmed, reclassified,
or unresolved with the evidence-grounded rationale, and do not silently discard
or average conflicting evidence.

## Completion shape

```json
{
"status": "answered | partial | blocked",
"category": "parent-assigned category",
"confirmed_occurrences": 0,
"distinct_sessions": 0,
"evidence": [{"file": "log path", "line_start": 1, "line_end": 1, "disposition": "confirmed | reclassified | unresolved", "rationale": "evidence-grounded basis", "sequence": "observed sequence", "blocker": "observed blocker"}],
"shared_pattern": "supported pattern or null",
"root_cause": "inference with basis or null",
"mitigations": ["concrete mitigation"],
"conflicts": ["material conflicting evidence"],
"stop_reason": "all supplied indicators resolved | evidence exhausted | concrete blocker",
"unknowns": ["unresolved indicator"]
}
```
34 changes: 34 additions & 0 deletions src/autoskillit/agents/pr-source-reader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: pr-source-reader
description: "Use when one parent-specified PR source artifact must yield bounded evidence."
tools: [Read]
model: sonnet
maxTurns: 80
codex:
model: gpt-5.6-luna
reasoning_effort: xhigh
sandbox_mode: read-only
---

# PR source reader

Read only the source artifact named by the parent. Extract the requested sections
faithfully and keep source headings or other location cues with each result. Do not
inspect other repository files, modify anything, use GitHub, or make the final PR
summary. If the artifact is missing or cannot answer a requested field, preserve
that gap instead of guessing. Mark each value as a literal extraction or bounded
summary and keep interpretation out of both. Account for every requested field in
the evidence or coverage gaps, then state why reading stopped.

## Completion shape

```json
{
"status": "answered | partial | blocked",
"source": "parent-supplied path",
"evidence": [{"field": "requested field", "value": "literal or bounded summary", "representation": "literal | summary", "location": "heading or line cue"}],
"coverage_gaps": ["requested field not resolved and why"],
"stop_reason": "requested fields covered | artifact exhausted | concrete blocker",
"unknowns": ["unresolved field or concrete blocker"]
}
```
33 changes: 33 additions & 0 deletions src/autoskillit/agents/pr-synthesizer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
name: pr-synthesizer
description: "Use when collected PR source evidence needs an overall pull request summary."
tools: [Read]
model: sonnet
maxTurns: 80
codex:
model: gpt-5.6-terra
reasoning_effort: high
sandbox_mode: read-only
---

# PR synthesizer

Synthesize only the evidence supplied by the parent into a concise overall pull
request summary. Do not inspect the repository or GitHub, introduce unsupported
claims, write files, or create the pull request. Preserve material uncertainty and
conflicts in the supplied evidence. Trace every material summary claim to supplied
evidence locations, keep observations distinct from upstream inferences, and return
`partial` when coverage gaps prevent a complete summary.

## Completion shape

```json
{
"status": "answered | partial | blocked",
"summary": "two or three evidence-grounded sentences",
"evidence_locations": ["supplied source and location supporting the summary"],
"conflicts": ["material conflict preserved from supplied evidence"],
"stop_reason": "summary supported | evidence exhausted | concrete blocker",
"unknowns": ["material unresolved point"]
}
```
2 changes: 1 addition & 1 deletion src/autoskillit/agents/repository-impact-profiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: repository-impact-profiler
description: "Terminal read-only specialist for repository impact and consumer-surface profiling."
tools: [mcp__autoskillit__submit_exploration_query, mcp__autoskillit__get_exploration_page, mcp__autoskillit__resume_exploration_context]
model: sonnet
maxTurns: 20
maxTurns: 80
codex:
model: gpt-5.6-luna
reasoning_effort: max
Expand Down
34 changes: 34 additions & 0 deletions src/autoskillit/agents/research-source-reader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: research-source-reader
description: "Use when one parent-specified research artifact must yield bounded evidence."
tools: [Read]
model: sonnet
maxTurns: 80
codex:
model: gpt-5.6-luna
reasoning_effort: xhigh
sandbox_mode: read-only
---

# Research source reader

Read only the research artifact named by the parent. Extract the requested report
or experiment-plan fields faithfully, retaining headings or other location cues.
Do not inspect unrelated files, synthesize a recommendation, select lenses, or
modify anything. Report absent or ambiguous fields without filling them in. Mark
each value as a literal extraction or bounded summary and keep interpretation out
of both. Account for every requested field in the evidence or coverage gaps, then
state why reading stopped.

## Completion shape

```json
{
"status": "answered | partial | blocked",
"source": "parent-supplied path",
"evidence": [{"field": "requested field", "value": "literal or bounded summary", "representation": "literal | summary", "location": "heading or line cue"}],
"coverage_gaps": ["requested field not resolved and why"],
"stop_reason": "requested fields covered | artifact exhausted | concrete blocker",
"unknowns": ["unresolved field or concrete blocker"]
}
```
37 changes: 37 additions & 0 deletions src/autoskillit/agents/research-synthesizer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
name: research-synthesizer
description: "Use when collected research evidence needs a direction and experiment-lens recommendation."
tools: [Read]
model: sonnet
maxTurns: 80
codex:
model: gpt-5.6-terra
reasoning_effort: xhigh
sandbox_mode: read-only
---

# Research synthesizer

Use only the report and experiment-plan evidence supplied by the parent. Produce
the requested directional recommendation or lens selection without inspecting the
repository, inventing findings, writing files, or invoking a lens. Select lens
slugs only from the parent's allowed table and state when the supplied evidence is
insufficient. Keep sourced findings, inference, and recommendation distinct; cite
the supplied evidence locations behind the recommendation, surface conflicts, and
abstain rather than collapse unresolved evidence into a direction.

## Completion shape

```json
{
"status": "answered | partial | blocked",
"findings": ["source-grounded finding kept distinct from inference"],
"recommendation": "one to three evidence-grounded sentences, or null",
"selected_lenses": ["allowed-lens-slug"],
"rationale": "brief evidence-grounded rationale",
"evidence_locations": ["supplied source and location supporting the recommendation"],
"conflicts": ["material conflict preserved from supplied evidence"],
"stop_reason": "recommendation supported | evidence exhausted | concrete blocker",
"unknowns": ["material unresolved point"]
}
```
2 changes: 1 addition & 1 deletion src/autoskillit/agents/semantic-code-navigator.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: semantic-code-navigator
description: "Terminal read-only specialist for structural and semantic repository navigation."
tools: [mcp__autoskillit__submit_exploration_query, mcp__autoskillit__get_exploration_page, mcp__autoskillit__resume_exploration_context]
model: sonnet
maxTurns: 20
maxTurns: 80
codex:
model: gpt-5.6-luna
reasoning_effort: max
Expand Down
6 changes: 4 additions & 2 deletions src/autoskillit/core/types/_type_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,11 @@ class BackendCapabilities:
}
)

CODEX_MODEL_ALIASES_LAST_VERIFIED: str = "2026-08-10"
CODEX_MODEL_ALIASES_LAST_VERIFIED: str = "2026-08-13"

CODEX_VALID_MODEL_IDS: frozenset[str] = frozenset({"gpt-5.5", "gpt-5.6-luna", "gpt-5.6-sol"})
CODEX_VALID_MODEL_IDS: frozenset[str] = frozenset(
{"gpt-5.5", "gpt-5.6-luna", "gpt-5.6-sol", "gpt-5.6-terra"}
)
CODEX_VALID_REASONING_EFFORTS: frozenset[str] = frozenset(
{"low", "medium", "high", "xhigh", "max", "ultra"}
)
Expand Down
2 changes: 1 addition & 1 deletion src/autoskillit/core/types/_type_protocols_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ def setup_session_dir(
parent_sandbox_mode: str = "workspace-write",
explorer_binding_env: Mapping[str, Mapping[str, str]] | None = None,
execution_role: SkillExecutionRole = SkillExecutionRole.SESSION,
) -> None: ...
) -> frozenset[str] | None: ...

def refresh_explorer_binding_env(
self,
Expand Down
58 changes: 56 additions & 2 deletions src/autoskillit/execution/backends/_codex_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import hashlib
import json
import tomllib
from collections.abc import Mapping
from pathlib import Path
from types import MappingProxyType
Expand Down Expand Up @@ -35,6 +36,12 @@

CODEX_MCP_STARTUP_TIMEOUT_SEC: float = 30.0

CODEX_SPAWNABLE_BUILT_IN_AGENT_NAMES = ("default", "explorer", "worker")
_CODEX_RESERVED_ONLY_AGENT_NAMES = frozenset({"review", "reviewer"})
_CODEX_AGENT_NAME_COLLISIONS = (
frozenset(CODEX_SPAWNABLE_BUILT_IN_AGENT_NAMES) | _CODEX_RESERVED_ONLY_AGENT_NAMES
)

# The configured history-retention requirement is derived from the largest
# measured recipe exemption plus explicit serialized-response headroom.
_MAX_RESPONSE_BACKSTOP_EXEMPTION_BYTES: int = max(
Expand Down Expand Up @@ -501,8 +508,6 @@ def _serialize_toml(data: dict[str, Any]) -> str:


def _read_codex_config(path: Path) -> ReadResult:
import tomllib

try:
raw_bytes = path.read_bytes()
except FileNotFoundError:
Expand All @@ -515,6 +520,55 @@ def _read_codex_config(path: Path) -> ReadResult:
return ReadResult.ok(data)


def effective_codex_agent_names(session_dir: Path) -> frozenset[str]:
"""Return roles backed by readable TOML in the finalized generated home."""
config = tomllib.loads((session_dir / "config.toml").read_text(encoding="utf-8"))
configured_agents = config.get("agents", {})
if not isinstance(configured_agents, dict):
raise ValueError("Codex config agents table must be a mapping")

effective = set(CODEX_SPAWNABLE_BUILT_IN_AGENT_NAMES)
for name, registration in configured_agents.items():
if not name.strip() or not isinstance(registration, dict):
logger.warning(
"codex_agent_registration_ignored",
agent_name=name,
reason="invalid_registration",
)
continue
config_file = registration.get("config_file")
if not isinstance(config_file, str) or not config_file.strip():
logger.warning(
"codex_agent_registration_ignored",
agent_name=name,
reason="invalid_config_file",
)
continue
target = Path(config_file)
if not target.is_absolute():
target = session_dir / target
try:
if not target.is_file():
logger.warning(
"codex_agent_registration_ignored",
agent_name=name,
path=str(target),
reason="missing_config_file",
)
continue
tomllib.loads(target.read_text(encoding="utf-8"))
except (OSError, UnicodeDecodeError, tomllib.TOMLDecodeError) as exc:
logger.warning(
"codex_agent_config_unreadable",
agent_name=name,
path=str(target),
error_type=type(exc).__name__,
)
continue
effective.add(name)
return frozenset(effective)


def _write_codex_config(path: Path, data: dict[str, Any], *, source: ReadResult) -> None:
if source.is_corrupt:
raise ValueError(
Expand Down
3 changes: 2 additions & 1 deletion src/autoskillit/execution/backends/claude.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,10 +513,11 @@ def setup_session_dir(
parent_sandbox_mode: str = "workspace-write",
explorer_binding_env: Mapping[str, Mapping[str, str]] | None = None,
execution_role: SkillExecutionRole = SkillExecutionRole.SESSION,
) -> None:
) -> frozenset[str] | None:
del execution_role
if explorer_binding_env:
raise ValueError(_EXPLORER_BINDING_REJECTION_MESSAGE)
return None

def refresh_explorer_binding_env(
self,
Expand Down
Loading
Loading