Skip to content

Add context layer for prompt assembly and tool execution gating#26

Merged
jbreite merged 11 commits into
mainfrom
feat/context-layer
Apr 12, 2026
Merged

Add context layer for prompt assembly and tool execution gating#26
jbreite merged 11 commits into
mainfrom
feat/context-layer

Conversation

@jbreite
Copy link
Copy Markdown
Owner

@jbreite jbreite commented Apr 10, 2026

Summary

Introduces src/context/ — a new module that handles two concerns most agent loops end up reinventing:

  1. Static system prompt assembly (buildSystemContext) — discovers project docs (AGENTS.md / CLAUDE.md), captures an environment snapshot (cwd, shell, platform, git), and builds tool guidance. Runs once at init so the system prompt stays stable for Anthropic prompt caching.
  2. Dynamic per-step layers (withContext / applyContextLayers) — wrap any ToolSet with ContextLayer gates (beforeExecute) and transforms (afterExecute). Ships createExecutionPolicy (plan-mode blocking, custom deny predicates) and createOutputPolicy (truncation, redirection hints, optional disk stash). createPrepareStep composes compaction + context-status + plan-mode hints into an AI SDK PrepareStepFunction without ever mutating the system prompt.

New public API

Types: ContextLayer, ExecutionPolicyConfig, OutputPolicyConfig, StashOutputConfig, InstructionDiscoveryConfig, DiscoveredInstructions, EnvironmentContext, EnvironmentContextConfig, ToolGuidanceConfig, SystemContextConfig, SystemContext, PrepareStepConfig.

Functions: withContext, applyContextLayers, createExecutionPolicy, createOutputPolicy, discoverInstructions, collectEnvironment, formatEnvironment, buildToolGuidance, buildSystemContext, createPrepareStep.

All re-exported from src/index.ts. AgentConfig.context in src/types.ts wires the layers automatically when provided.

Docs refresh

  • Rewrites root AGENTS.md as a contributor guide — drops ~400 lines of consumer API examples that belonged in README.md, adds a Core Principles section (type safety, testability, error-return convention, folder-AGENTS.md invariant), and documents the commit / lint / test / symlink CI gates.
  • Promotes root CLAUDE.md to a symlink → AGENTS.md, matching the convention enforced everywhere else by scripts/check-agents-md.sh.
  • Adds src/context/AGENTS.md + CLAUDE.md symlink documenting internal architecture, design patterns, and per-task modification steps.
  • Adds a Context Layer section to README.md with three worked examples (building a system prompt, wrapping tools with layers, composing prepareStep) plus API Reference entries for all new exports.

Test coverage

7 new test files under tests/context/ (2,089 lines total):

  • build-context.test.ts — system prompt assembly, section enable/disable, combined output
  • execution-policy.test.ts — plan-mode blocking, custom predicates
  • output-policy.test.ts — truncation, hints, stash-to-disk, custom builders
  • prepare-step.test.ts — compaction, context-status injection, plan-mode hint, extend composition
  • with-context.test.ts — layer wrapping, gate short-circuit, transform pipe, no-execute passthrough
  • parallel.test.ts — layer isolation under concurrent tool calls
  • integration.test.ts — end-to-end with a real ToolSet + sandbox

Full suite: 558 passed, 27 skipped (sandbox smoke tests).

Breaking changes

None. All new surface is additive — existing createAgentTools signatures unchanged, no tool input/output schemas touched, no Sandbox interface changes.

Test plan

  • bun run typecheck — clean
  • bun run check:ci (Biome) — clean
  • bun run check:agents — clean
  • bun run test — 558 passed, 27 skipped
  • Manual: run examples/basic.ts with the new buildSystemContext + applyContextLayers wiring
  • Manual: verify Anthropic prompt cache hits stay stable across turns when using buildSystemContext
  • Verify createPrepareStep compaction path under a long conversation

🤖 Generated with Claude Code

Introduces src/context/ with two distinct concerns:

- Static system prompt assembly: buildSystemContext composes discovered
  AGENTS.md/CLAUDE.md instructions, environment snapshot (cwd, shell, git),
  and tool guidance into a single string. Runs once at init so the system
  prompt stays stable for Anthropic prompt caching.

- Dynamic per-step layers: withContext/applyContextLayers wrap any ToolSet
  with ContextLayer gates (beforeExecute) and transforms (afterExecute).
  Ships createExecutionPolicy (plan-mode blocking) and createOutputPolicy
  (truncation, redirection hints, optional disk stash). createPrepareStep
  composes compaction + context-status + plan-mode hints into an AI SDK
  PrepareStepFunction without ever mutating the system prompt.

Also refreshes repo docs:

- Rewrites root AGENTS.md as a contributor guide (dropped ~400 lines of
  consumer API examples that belonged in README), adds Core Principles
  section covering type safety, testability, error-return convention,
  and the folder-AGENTS.md documentation invariant.
- Promotes root CLAUDE.md to a symlink -> AGENTS.md, matching the
  convention enforced everywhere else by scripts/check-agents-md.sh.
- Adds src/context/AGENTS.md + CLAUDE.md symlink documenting internal
  architecture, design patterns, and common modifications.
- Adds README section documenting buildSystemContext, layer composition,
  and prepareStep wiring, plus API reference entries for new exports.

Test coverage: 7 new test files under tests/context/ covering layer
wrapping, gate short-circuit, transform pipe, parallel isolation,
output policy truncation/stash, execution policy, prepare step
composition, and end-to-end integration with a real ToolSet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
bashkit-docs Ready Ready Preview, Comment Apr 12, 2026 2:13pm

Four spots used result.messages! without first narrowing result itself,
which PrepareStepFunction types as PrepareStepResult | undefined. The
surrounding expect(result?.messages).toBeDefined() doesn't propagate
narrowing to TypeScript. Added explicit non-null assertions on result.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clarifies that scripts use no hyphens (typecheck, not type-check) and
lists the full set of package.json script names. Adds a one-liner for
running all four pre-push CI gates locally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jbreite and others added 7 commits April 12, 2026 09:31
The fallback branch in injectTruncatedOutput replaced the entire result
object with { _truncated, _hint }, silently erasing fields like { error }
and breaking the return-error-not-throw contract. Spread the original
result so all fields are preserved alongside truncation metadata.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The stashOutput mkdir -p call interpolated the directory path unescaped
into a shell command, allowing spaces, $(), backticks, or semicolons in
pathFor() results to break or execute unintended fragments. Single-quote
the path with interior quote escaping.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Make planModeState optional in createExecutionPolicy so shouldBlock
works standalone. Update createAgentTools wiring to install the layer
when either plan mode or a custom execution policy is configured.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wrap the stash-to-disk path in try/catch so mkdir or writeFile failures
log a warning instead of converting a successful tool result into an
unhandled exception.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The JSDoc comments implied default-on behavior but the implementation
disables both when omitted. Update comments to say so explicitly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
buildSystemContext called formatEnvironment without passing the custom
fields from EnvironmentContextConfig, silently dropping them from the
prompt output.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jbreite jbreite marked this pull request as ready for review April 12, 2026 14:09
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jbreite jbreite merged commit 260de7a into main Apr 12, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant