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
PATHcarries over. - A GUI-launched agent (no shell profile sourced) can miss
~/.local/binor wherever the binaries landed. If session context or activity records are missing, checkPATHfirst. - The daemon also needs both binaries server-side: it shells
feltfor fiber content and writes, andshuttlefor 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.