Skip to content

Working with Agents

felt ships as a plugin for Claude Code and Codex. The plugin makes an agent fiber-aware. It shows the agent the active fibers at session start. It nudges the agent toward felt instead of raw file edits. It keeps fiber timestamps honest when the agent edits a fiber file directly.

Requirement: both Go CLIs on PATH

The plugin uses two binaries. Felt-owned hooks call felt; activity and commit hooks call shuttle. Each adapter fails quietly when its binary is absent.

  • In a terminal-launched session this is usually fine — your shell's PATH carries over.
  • A GUI-launched agent (no shell profile sourced) can miss ~/.local/bin or wherever the binaries landed. If session context or activity records are missing, check PATH first.
  • The daemon also needs both binaries server-side: it shells felt for fiber content and writes, and shuttle for resolved reads and orchestration. A missing executable degrades the corresponding board operations.

Installing the plugin

felt setup claude    # Claude Code
felt setup codex     # Codex
felt setup pi        # pi (@earendil-works/pi-coding-agent)

The first two wrap the official plugin-marketplace flow:

# Claude Code
claude plugin marketplace add cailmdaley/felt[#v<tag>]
claude plugin install felt@cailmdaley-felt

# Codex
codex plugin marketplace add cailmdaley/felt[@v<tag>]
codex plugin add felt@cailmdaley-felt

felt setup pi wraps pi's package manager:

pi install git:github.com/cailmdaley/felt[@v<tag>]

None of them need a local checkout. Felt acquires GitHub sources into a disposable checkout, validates the complete plugin payload, promotes one local generation, and then asks the harness CLI to install it. A tagged felt binary pins acquisition to the matching tag; a dev build tracks the default branch, and every promoted payload records its resolved commit and content digest. An interrupted native activation is reconciled from the last known-good promoted generation before setup continues; felt setup receipt --json rejects pending or mismatched source/cache generations.

All three commands are idempotent, so re-running is safe. All take --uninstall to remove what they installed. felt uninstall clears the harnesses at once, and serves as the general inverse.

Codex asks you to trust the hooks

Codex reviews a plugin's hooks before it will run them. Your next interactive Codex session shows a review screen for felt's; accept it once and the setting persists. Until you do, the skills load but the hooks stay dormant — no SessionStart fiber context, and nothing recorded for shuttle's activity stream. A headless codex exec session can't show the prompt, so trust felt's hooks from an interactive session first.

install.sh (the curl installer) runs both commands automatically for whichever CLI it finds on PATH, with no opt-out flag — see Getting started.

Skills only

felt setup skills [--target <dir>]

Symlinks felt's skills into a directory without touching the plugin marketplace — ~/.claude/skills by default. Useful if you want the skill content without the hooks.

Plugin contents

One plugin directory serves Claude Code and Codex; one package manifest serves pi (the repo-root package.json, whose pi key points at the same skill tree and at extensions/pi/). Both bundle the same two skills; hooks on Claude/Codex correspond to extension events on pi.

Skills

  • felt — the substrate practice: filing fibers, updating outcomes and bodies, additional YAML fields, end-of-session sweeps, maintenance passes.
  • shuttle — the dispatch practice: authoring constitutions, worker dispatch, operating the board. Only relevant once you're using the optional shuttle layer.

Skills activate the way any Claude Code / Codex / pi skill does — by the harness matching the user's request against the skill's description. felt setup skills (above) links these into your skills directory independent of the plugin.

Hooks (Claude Code, Codex)

Hook Event Effect
session.sh SessionStart Wraps felt session's plain-text context (active + recently-touched fibers) in the harness's additionalContext envelope
remind.sh PreToolUse Gates the first non-skill tool call in a felt-enabled project until the felt skill has activated this session; a pass-through everywhere else
touch.sh PostToolUse (Edit/Write/MultiEdit) Stamps a fiber's updated-at when the agent edits its markdown file directly, so hand-edits count toward recency the same as felt edit does
event.sh SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, Stop, SubagentStop, Notification, SessionEnd Calls shuttle hook event to append one JSON line to ~/.shuttle/events.jsonl and handle Shuttle mailbox registration/delivery; writes nothing unless ~/.shuttle exists
commit.sh PostToolUse (Bash) Calls shuttle hook commit to record commits in ~/.shuttle/commits.jsonl

The logic lives in the owning binary, not the script. remind.sh and touch.sh call felt hook pretool and felt hook posttool; event.sh and commit.sh call shuttle hook event and shuttle hook commit. session.sh wraps felt session with a jq -Rs pipeline, and falls back to felt hook session when jq is absent.

Extension events (pi)

On pi the same behavior comes from extensions/pi/index.ts, loaded via the package manifest. The division of labor is identical — the binary owns the logic, the adapter owns the plumbing:

pi event Effect
session_start Emits the session-start event for shuttle's activity stream
before_agent_start Injects felt session's context once per session (pi has no SessionStart context envelope); emits the prompt-submit event
tool_call The activation gate: in a felt-enabled project, blocks tools until the model reads the felt SKILL.md or runs /skill:felt — pi activates skills by reading, not by a Skill tool, so the gate lives in the extension rather than the binary
tool_result (edit/write) Recency stamping via felt hook posttool
tool_result (bash) Commit ledger via shuttle hook commit; post-tool-use event via shuttle hook event
agent_end, session_shutdown Stop / session-end events for the activity stream

No pi equivalent exists for SubagentStop and Notification events; the activity stream simply carries fewer line types from pi sessions.

Note

Updating the CLIs updates hook behavior. felt update (and Homebrew's post-install) refresh both Go binaries and the plugin wiring together, so hooks always run against matching binaries. You only need to re-run felt setup claude/codex when the skill content changes, not when hook logic changes.

Full CLI surface

See the CLI reference for every felt and shuttle verb.