Skip to content

Replace get-session-context skill with a bundled TS deriver #653

Description

@williamthorsen

Problem

resolve-frontmatter.sh fails with a "precondition violated" error whenever the branch manifest is absent. The manifest is created exclusively as a side effect of the get-session-context skill, and consumer skills frame the invocation as a data lookup ("use get-session-context to obtain project_slug and artifact_base_dir"). When the agent has already read those values from .agents/preferences.yaml, the lookup framing makes the call appear redundant, the agent skips it, the manifest never gets written, and the next artifact-writing operation fails.

The structural cause is an asymmetry. Derivation logic lives in a Zero-Bash skill that only main agents can invoke. Consumers include subagents and bash scripts (resolve-frontmatter.sh) that cannot invoke skills. The manifest exists to bridge that gap, and the side-effect mandate exists to keep the bridge populated. Both are workarounds for putting the derivation in a place not every caller can reach.

Context

  • The get-session-context skill is at packages/agents/content/skills/get-session-context/SKILL.md. It both returns session metadata and persists the branch manifest as a side effect.
  • The dependent script is at packages/agents/content/scripts/resolve-frontmatter.sh.
  • The manifest schema and the side-effect mandate are documented in packages/agents/content/skills/_data/artifact-conventions.md § Subagent dispatch precondition.
  • Every value the manifest carries is mechanically derivable from the current branch name plus the merged contents of .agents/preferences.yaml and ~/.agents/preferences.yaml. No field requires agent reasoning.
  • The agents package already runs non-trivial skill logic through a bundle pattern. scripts/bundle-skill-helpers.ts builds TypeScript entries in src/<skill>/ into self-contained .mjs files under content/skills/<skill>/, using esbuild to inline workspace and node_modules dependencies. Three skills already use this pattern: kb-add, kb-retrieve, and update-jira-ticket.
  • The newer YAML parser (yaml 2.9.0, eemeli's package) is already used by @codeassembly/kb-core for frontmatter parsing and document-AST manipulation. The agents package currently uses the older js-yaml; this work introduces eemeli yaml as a direct dependency.
  • The preferences shape has a JSON schema at packages/agents/schemas/preferences.json, and a schema validator is already a devDependency (@hyperjump/json-schema).
  • The canonical ticket-ID extraction contract lives in _data/ticket-id-extraction.md and is currently implemented in bash at packages/agents/content/scripts/get-ticket-id.sh. The TS deriver will reimplement the contract in TypeScript with its own tests. Both implementations conform to the same documented spec; consolidating them is out of scope.
  • Consumer skills with manifest-dependent step-1 invocations (about 20): align-ticket-with-implementation, condense-branch, create-devlog, create-pr (and create-gh-pr / create-bitbucket-pr), create-ticket, design-and-plan, find-orchestration-savings, merge-pr, orchestrate, plan, plan-orchestrable-steps, refine-plan, respond-to-review, review-branch, review-pr, save-artifact, save-plan, summarize-change, summarize-chat, wrap-up.

Proposed solution

Move the derivation contract into a TypeScript helper bundled via the existing skill-helper pipeline, and retire the asymmetry that made the side-effect mandate necessary.

  1. Add src/derive-session-context/ containing the TypeScript entry point, pure derivation logic, an eemeli-yaml-based preferences reader that validates against schemas/preferences.json, a TypeScript implementation of the ticket-ID extraction contract per _data/ticket-id-extraction.md, and vitest unit tests covering every manifest edge case documented in the current get-session-context skill.

  2. Register the new entry in bundle-skill-helpers.ts so the build produces content/skills/derive-session-context/derive-session-context.mjs. The bundled .mjs is self-contained and runs on stock Node 24+ with no monorepo packages required at runtime.

  3. Add eemeli yaml as a direct dependency of @codeassembly/agents (already transitive via kb-core).

  4. Modify resolve-frontmatter.sh to invoke the bundled deriver on cache miss instead of failing. The manifest remains the fast path; failure to find it becomes a recovery rather than a hard stop.

  5. Deprecate and remove the get-session-context skill. Update every consumer skill's step-1 instruction to invoke the bundled deriver (or read the resulting manifest) instead. Once no consumers reference the skill, remove the skill file.

  6. Rewrite artifact-conventions.md § Subagent dispatch precondition to describe the new architecture: Any caller writes the manifest on demand; no dispatch-time precondition exists.

The outcome is a single derivation implementation, callable identically by main agents, subagents, and shell scripts. The side-effect mandate goes away because no caller depends on another caller having run.

Acceptance criteria

  • src/derive-session-context/ exists with TypeScript source covering: an eemeli-yaml-based preferences reader (validating against schemas/preferences.json), a TS implementation of the ticket-ID extraction contract from _data/ticket-id-extraction.md, and a manifest composer. Vitest unit tests cover every manifest edge case documented in get-session-context/SKILL.md (Jira-style, bare-numeric with # prefix, bare-numeric with Jira-style prefix, no ticket, custom artifact paths, sub-ticket suffix, author-prefixed lowercase).
  • The deriver writes the manifest at the canonical path and emits the same JSON to stdout, matching the existing manifest schema.
  • The new entry is registered in bundle-skill-helpers.ts; a smoke-test invocation is registered in smoke-test-skill-helpers.ts; the build produces a working .mjs under content/skills/derive-session-context/.
  • eemeli yaml is added as a direct dependency of @codeassembly/agents.
  • resolve-frontmatter.sh invokes the bundled deriver on cache miss; the precondition error path is removed.
  • Every consumer skill's step-1 instruction is updated to invoke the bundled deriver or read the manifest directly.
  • The get-session-context skill file is removed; no references to it remain in skill files, _data/ docs, or other agents content.
  • artifact-conventions.md § Subagent dispatch precondition is rewritten to describe the new architecture.
  • New and modified behavior in this change is covered by tests (vitest unit tests for the deriver and preferences reader; smoke test for the bundle).
  • Documentation, help text, and usage examples for get-session-context are removed; no orphan references remain.

Metadata

Metadata

Labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions