Skip to content

Preserve workflow context during native skill expansion - #118

Merged
swerner merged 6 commits into
mainfrom
codex/skill-context
Oct 14, 2026
Merged

swerner merged 6 commits into
mainfrom
codex/skill-context

Conversation

@swerner

@swerner swerner commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Prior-stage text such as smoke-tested via a /tmp build or feedback mentioning /commit must remain workflow data. Native agent turns now send only the authored prompt through Pebble's skill expansion, keeping the fidelity preamble, for_each item, and output contract outside it. A leading authored /commit still works with a nonempty preamble, and a template without {{user_input}} cannot discard surrounding context.

Absent prompt segments are omitted instead of emitting empty text blocks, which Anthropic rejects. This applies to preambles, suffixes, and empty authored prompts with nonempty context.

Generated repair turns bypass expansion. User-delivered follow-ups retain leading-command support. ACP keeps its existing single assembled text block, and one-shot prompt behavior is unchanged.

Depends on Pebble commit 679cfd1, currently on codex/skill-command-boundary. Keep this PR in draft until that dependency reaches Pebble main. The manifest retains the required branch = "main"; Cargo.lock pins the published commit. Related: lithoscomputer/pebble#37.

Thanks to @denkhaus for the original report, leading-command rule, and regression cases in fabro-sh/fabro#784.

Validation:

  • Reproduced the original CI failures in embedding_readiness and fabro_differential::fallback_failover_matches_the_pinned_fabro; both pass with the fix. The compatibility CI job also passed after the initial empty-context correction.
  • cargo nextest run --locked --workspace --all-targets --all-features --no-tests=pass --no-fail-fast: 1,755 passed, one watchdog timing test failed under load, nine skipped. The watchdog test passed in the serial rerun; no watchdog code changed.
  • Final serial regression run: 34 passed, covering all native Pebble tests, the combined embedding workflow, all Fabro differential comparisons, and the watchdog rerun. Request assertions cover absent preamble/suffix blocks and an empty authored prompt with a preamble.
  • cargo test --locked --workspace --all-features --doc: passed.
  • cargo clippy --locked -p petri-attractor-steps --all-targets --all-features -- -D warnings: passed.
  • mise run fmt:check and patch whitespace checks: passed.
  • Environment-gated tests retain their existing gates. The local full workspace release gate was not run.

Fabro follow-up: update docs/public/agents/skills.mdx, “Slash syntax (user input)” and lifecycle step 3. Commands are recognized only at the beginning of authored input after leading whitespace; later slash tokens are ordinary arguments/text. Replace the “preceded by whitespace” and “only one skill reference” rules. Document that workflow preambles, item data, and output contracts stay outside expansion, even for templates without a placeholder. Petri's Attractor format reference is updated here.

@swerner
swerner marked this pull request as ready for review October 13, 2026 20:57
Add `Preamble::prefix` so agent and one-shot prompt nodes share the rule
that joins the preamble to the node's prompt. Remove the now-unused
`AgentConfig::assemble` and keep `Prompt::assembled` private to the
backend.

In the tests, add a `skill_runtime` helper that always isolates the Fabro
home. Replace the boolean context helper with a shared turn runner and a
no-expansion check. Move the ACP test's output settings into its DOT
source and use the existing `run` helper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@swerner

swerner commented Oct 14, 2026

Copy link
Copy Markdown
Contributor Author

Simplify pass

Pushed e028683 with cleanups from a reuse, simplification, efficiency, and altitude review. Behavior is unchanged.

Fixed

  • Preamble separator in one place. session_prompt repeated the "preamble, then a blank line unless empty" rule from Preamble::prompt. A new Preamble::prefix holds the rule. Preamble::prompt and the agent's prompt builder both use it, so agent and one-shot prompt nodes cannot drift apart.
  • Removed unused AgentConfig::assemble. It had no callers after this change, and its doc no longer described what native agents receive. The doc moved to session_prompt. Prompt::assembled is now private and reuses its first buffer instead of calling format!.
  • Isolated Fabro home for skill tests. A new skill_runtime helper always installs the isolated FabroHome. A future skill test cannot pick up a developer's real ~/.fabro skills by forgetting it.
  • No boolean test helper. check_native_skill_context(prior, authored, activates) is now native_skill_turn, which runs the turn and checks the shared context. The three cases that should not expand use check_no_expansion. The expansion case keeps its assertions inline.
  • ACP test. output_schema and output_retries are now DOT attributes, and the test uses the existing run helper.

Skipped

  • Empty text blocks. Dropping them belongs in the Anthropic codec or Pebble's CodingInput assembly, not in Petri. That fix is in another repo, so prompt_content stays for now.
  • Moving or renaming Prompt. Low value, and it would churn the module layout.
  • Looped test cases. Splitting them into separate tests is a minor speed gain, and the loops match existing style.
  • Shared node_config in tests/agent.rs. Only worth doing if the helper moves into testkit.
  • Shared item and contract trailer for agent and prompt nodes. That duplication was there before this PR.
  • An assert_success helper. Only worth it file-wide.

Verification

  • cargo nextest run -p petri-attractor-steps --all-features: 201 passed. The sandbox driver plugins were set.
  • cargo clippy -p petri-attractor-steps --all-targets --all-features -- -D warnings: clean.
  • mise run fmt: applied.
  • Not run locally: the Fabro differential and embedding readiness suites. The machine ran out of disk while linking them. CI covers them.

🤖 Generated with Claude Code

@swerner
swerner merged commit 56ec384 into main Oct 14, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant