Skip to content

feat(agent): add-on system with rtk as the first built-in#2279

Draft
joshsny wants to merge 1 commit into
mainfrom
posthog-code/add-ons-with-ztk
Draft

feat(agent): add-on system with rtk as the first built-in#2279
joshsny wants to merge 1 commit into
mainfrom
posthog-code/add-ons-with-ztk

Conversation

@joshsny
Copy link
Copy Markdown
Contributor

@joshsny joshsny commented May 21, 2026

Problem

PostHog Code tasks need a way to opt in to extra agent behaviors per-task. Today the only knobs are buried inside claudeCode.options or mcpServers, with no symmetric path that works for both local and cloud or for both Claude and Codex. The first concrete use case is rtk, a CLI proxy that wraps shell commands to reduce LLM token consumption, but the surface should support future capabilities (PostHog-aware system-prompt addenda, MCP-based integrations, etc.) without bespoke plumbing each time.

Changes

Adds a typed add-on system to @posthog/agent and a task.options.add_ons configuration channel.

Architecture

  • Unified registry, per-adapter capability honoring. packages/agent/src/add-ons/ defines AddOnDefinition (name, options schema, contribute) and AddOnRegistry. The same registry is consumed by both Claude and Codex adapters; each honors only the slots it can:
    • Claude: env, systemPromptAppend, preToolUse, postToolUse
    • Codex: systemPromptAppend only — codex-acp exposes no pre/post-tool interception, so add-ons that need command rewriting declare supportedAdapters: ["claude"] and are silently skipped on Codex.
  • Single transport channel. Add-on config rides on _meta.addOns of the ACP newSession request alongside the existing claudeCode / jsonSchema channels. Resolved in ClaudeAcpAgent.createSession (Claude) and CodexAcpAgent.{newSession, loadSession, unstable_resumeSession, unstable_forkSession} (Codex).
  • Cloud parity. AgentServerConfig.addOns and a matching --addOns <json> CLI flag on the sandbox agent server forward the same JSON onto the cloud newSession.
  • First built-in: rtk. rtkAddOn contributes a Claude PreToolUse hook that rewrites tool_input.command for Bash tool calls into rtk run [--skip-permissions] -- <original>. Options: binaryPath, skipPermissions. Binary resolution trusts $PATH.
  • Task model. Adds an optional options?.add_ons field to both the agent-package Task type and the apps/code shared Task type so the renderer and main process can populate it ahead of the Django migration.

Hook ordering invariant

Add-on PreToolUse hooks run BEFORE the built-in permission gate so a rewrite (e.g. rtk wrapping a Bash command) is visible to the permission check and to the cloud signed-commit guard.

Follow-ups not in this PR

  • Django migration. The Django Task model needs options = models.JSONField(default=dict, blank=True) plus a matching serializer field.
  • UI. No task-creation UI changes yet — task.options.add_ons is settable from code but there's no "Add-ons" disclosure in the task input form.

How did you test this?

  • 19 unit tests in registry.test.ts and rtk.test.ts: empty config, env merging (last-wins), systemPromptAppend concatenation, pre/postToolUse aggregation, adapter gating, unknown-name warnings, options-parse failures, prepare/contribute ordering, duplicate-registration rejection, Bash command rewriting, non-Bash pass-through, --skip-permissions, Codex adapter gating, end-to-end registry resolution, double-wrap protection, single-quote path escaping.
  • 19 integration tests covering the adapter wiring:
    • Claude buildSessionOptions: PreToolUse ordering invariant (add-on hooks BEFORE built-in permission gate), PostToolUse appending, systemPromptAppend across both string and preset shapes, env merge with last-write-wins, no-contribution regression guard.
    • appendToSystemPrompt: all four branches as a focused unit test.
    • Codex: _meta.addOns forwarded to the registry on all four session entry points, systemPromptAppend concatenated into _meta.systemPrompt, env contribution warned-and-dropped (codex-acp env is fixed at spawn), empty-contribution pass-through.
  • pnpm --filter agent typecheck clean.
  • Live rtk-wrapped session against Claude not yet run; a smoke test with a real rtk binary is a sensible pre-merge check.

Publish to changelog?

no


Created with PostHog Code

@joshsny joshsny closed this May 25, 2026
@joshsny joshsny force-pushed the posthog-code/add-ons-with-ztk branch from 5ce03ed to 750d4ae Compare May 25, 2026 14:42
Adds a typed add-on system to @posthog/agent and a `task.options.add_ons`
configuration channel for opting in to extra agent behaviors per-task.

Architecture
- Unified registry, per-adapter capability honoring. `packages/agent/src/add-ons/`
  defines AddOnDefinition (name, options schema, contribute) and AddOnRegistry.
  Claude consumes every contribution slot (env / systemPromptAppend / preToolUse /
  postToolUse); Codex consumes only systemPromptAppend because codex-acp has
  no pre-execution tool interception. Add-ons that need command rewriting
  declare `supportedAdapters: ["claude"]` and are skipped on Codex with a log.
- Single transport channel. Add-on config rides on `_meta.addOns` of the ACP
  newSession request, resolved in ClaudeAcpAgent.createSession and Codex's four
  session entry points.
- Cloud parity. AgentServerConfig.addOns plus `--addOns <json>` on the sandbox
  agent server forward the same JSON to the cloud newSession.
- First built-in: rtk. A Claude PreToolUse hook wrapping Bash commands through
  the rtk token-reduction CLI (rtk-ai/rtk). Resolution trusts $PATH; options:
  `binaryPath`, `skipPermissions`.
- Task model. Adds an optional `options?.add_ons` field to the Task type in
  both agent-package and apps/code, ahead of the Django migration.

Tests
- 19 unit tests across registry.test.ts and rtk.test.ts.
- 19 integration tests covering adapter wiring: PreToolUse ordering invariant
  (add-on hooks run before the built-in permission gate), systemPromptAppend
  composition across string + preset shapes, env merge with last-write-wins,
  appendToSystemPrompt branch coverage, addOns forwarded through all four
  Codex session entry points (newSession, loadSession, unstable_resumeSession,
  unstable_forkSession), env contribution dropped+warned on Codex.

Merged in main (47 commits ahead) and resolved conflicts in options.ts
(adding the add-on slots alongside cloudMode) and codex-agent.ts (composing
applyAddOnContribution with applyStructuredOutput + applyLocalTools).

Generated-By: PostHog Code
Task-Id: de63edf0-0b52-40b4-9ffc-4758850b10d3
@joshsny joshsny changed the title feat(agent): add-on system with ztk as the first built-in feat(agent): add-on system with rtk as the first built-in May 25, 2026
@joshsny joshsny reopened this May 25, 2026
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