Reference for the Giant Squid Harness hook tentacles (bin/pd-hook-prompt, bin/pd-hook-pre-tool, bin/pd-hook-post-tool, bin/pd-hook-stop) — the per-vendor event contracts, dial resolution, output channels, loop guards, and test seams that govern how Port Daddy rides inside Claude Code, Gemini CLI, Codex CLI, and Antigravity lifecycles. Use when editing a tentacle, wiring a new hook event, debugging a hook that fired wrong (or not at all), or verifying vendor block contracts. NOT for operating Port Daddy on another project (use port-daddy-agent-skill) and NOT for general repo contribution mechanics (use port-daddy-internal-dev).
Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Reference for the Giant Squid Harness hook tentacles (bin/pd-hook-prompt, bin/pd-hook-pre-tool, bin/pd-hook-post-tool, bin/pd-hook-stop) — the per-vendor event contracts, dial resolution, output channels, loop guards, and test seams that govern how Port Daddy rides inside Claude Code, Gemini CLI, Codex CLI, and Antigravity lifecycles. Use when editing a tentacle, wiring a new hook event, debugging a hook that fired wrong (or not at all), or verifying vendor block contracts. NOT for operating Port Daddy on another project (use port-daddy-agent-skill) and NOT for general repo contribution mechanics (use port-daddy-internal-dev).
license
FSL-1.1-MIT
allowed-tools
Read,Bash,Grep,Glob,Edit,Write
metadata
{"category":"Coordination","tags":["port-daddy","giant-squid","hooks","tentacles","claude-code","gemini","codex","antigravity","sitrep","lifecycle"],"pairs-with":[{"skill":"port-daddy-agent-skill","reason":"Operating the harness (pd squid on, SITREP discipline) from any project."},{"skill":"port-daddy-internal-dev","reason":"Contributor invariants — release cargo, PR discipline, breaker doctrine — when editing these tentacles."}],"provenance":{"kind":"first-party","owners":["port-daddy"],"scope":"internal"},"authorship":{"maintainers":["port-daddy"]},"distribution":{"public":false,"note":"Repo-private. The tentacles are internal harness machinery; agents on other projects interact with them only through the public port-daddy-agent-skill."}}
Giant Squid Hooks — the four tentacles
The Giant Squid Harness (ADR-0091) does not run the agent loop. It sinks four
small POSIX-sh tentacles into each vendor CLI's native hook surface so that
coordination fires inside the vendor's own lifecycle:
Tentacle
Phase label
Fires on
Job
bin/pd-hook-prompt
PD TURN
turn start
Inject bounded coordination context, unread inbox/parley count, and the SITREP compulsion
bin/pd-hook-pre-tool
PD EDIT
before direct edits
Block foreign-locked files per the suggestibility dial
bin/pd-hook-post-tool
PD TRACE
(retired from lifecycles)
Legacy pheromone trace; staged for migration/debug only
bin/pd-hook-stop
PD CLOSE
turn end
Verify the SITREP table the prompt tentacle compelled
One reference file per tentacle carries the full per-vendor contract; start at
the hub: references/INDEX.md.
Driving Port Daddy as a coordination tool on another project — that is
port-daddy-agent-skill (its Giant Squid section covers pd squid on,
status, and repair from the operator side).
Repo-wide contributor mechanics (worktrees, PR ceremony, release surfaces) —
that is port-daddy-internal-dev.
The SessionStart Pilot hook (hooks/sessionstart-pilot.mjs) — related but a
Node hook with its own doctrine, not a tentacle.
The one source of truth for shapes
Every event name, tool matcher, timeout, and the Codex TOML block live in
— both injectors import from it:
lib/squid/hook-shape.ts
the headless adapter (lib/squid/adapter.ts) writes workspace/home configs
for claude -p / gemini -p / codex exec / agy -p voyages;
the interactive installer (cli/commands/hooks-install.ts) stages the
tentacles to ~/.port-daddy/bin/squid/ and points every provider config at
generated gate wrappers in ~/.port-daddy/bin/.
REGISTERED_TENTACLES (in lib/squid/hook-shape.ts) is the roster of
tentacles actually wired into lifecycles: prompt, pre-tool, and stop.
pd-hook-post-tool stays in TENTACLES (staged, diagnosable, removable) but
is deliberately NOT registered — see references/post-tool.md for the
fan-out incident that retired it.
Event map (all four vendors)
Purpose
Claude Code
Gemini CLI
Codex CLI
Antigravity (agy)
prompt
UserPromptSubmit
BeforeAgent
[[hooks.UserPromptSubmit]]
UserPromptSubmit
preTool
PreToolUse
BeforeTool
[[hooks.PreToolUse]]
PreToolUse
stop
Stop
AfterAgent
[[hooks.Stop]]
Stop (observe-only)
Timeout units differ: Gemini takes milliseconds, Claude/agy/Codex take
seconds. buildJsonHookMap and codexHooksTomlBlock in
lib/squid/hook-shape.ts encode this; never hand-write a hook entry.
The gate wrapper (why a tentacle is never called directly)
Interactive configs point at generated wrappers (see gateWrapperScript() in
cli/commands/hooks-install.ts), which no-op unless the daemon's readiness
lease matches its live PID, the Bosun heartbeat is fresh, and the cwd is
inside an explicitly armed project root. The wrapper also owns the
fail-open circuit breaker:
cooldown: 5 minutes, one half-open probe (lib/squid/debug.ts:34)
Every tentacle must complete comfortably under the 250 ms slow line or it
counts toward self-disable. Phase labels in wrapper debug events and breaker
notices: PD TURN / PD EDIT / PD TRACE / PD CLOSE — the debug reader
(lib/squid/debug.ts) validates the phase enum (turn|edit|trace|close) and
the hook-name regex, so a new tentacle that skips registration there is
silently invisible to pd squid debug status.
Shared doctrine (all tentacles)
Fail open, always. Any parse error, missing tool (jq, python3,
/usr/bin/time), or unverifiable input exits 0 with no output. A missed
coordination fact is degraded coordination; a crashed or hung CLI loop is a
broken product (ADR-0091 §Mitigation).
POSIX sh only.#!/bin/sh, set -u, no bashisms. jq is optional with a
python3 or sed fallback; the tentacles run under dash, BSD sh, and busybox.
Bounded output. Coordination content is capped (two facts + heading,
512 bytes in the prompt tentacle). The SITREP contract block is the one
deliberate exception — constant-size harness text riding outside the byte cap
(operator doctrine, 2026-08-22).
Codex stdout rule. Codex treats raw non-JSON stdout on exit 0 as invalid.
Any tentacle path that can run under Codex must emit either nothing or a
documented JSON shape on stdout. The universal block contract — exit 2 plus a
non-empty reason on stderr — is accepted by Claude, Gemini, and Codex,
and is the only block mechanism the tentacles use at Stop time.
The reason is a prompt. Whatever a blocking tentacle writes to stderr is
fed to the model as its next instruction. Write directives, not diagnostics:
the stop tentacle's block reason IS the SITREP directive (mirroring
bin/pd-hook-prompt's enforce text), never a transcript excerpt or an error
dump.
Dial resolution is shared shape. Both dials — suggestibility
(advisory|warn|enforce, pre-tool) and sitrep.endOfTurn (off|suggest|enforce,
prompt + stop) — resolve identically: env override first (PD_SUGGESTIBILITY
/ PD_SITREP), then a parent walk over agent.config.json →
.portdaddy/sitrep.json (or .portdaddy/suggestibility.json) →
.portdaddy/project.json, nearest directory wins, closed enum, malformed or
unreadable config falls toward the DEFAULT (enforce), never toward silence.
The Stop tentacle's loop-guard doctrine
bin/pd-hook-stop is the only tentacle that can block at a point where a
naive implementation could wedge the CLI in a block-loop. It is guarded twice:
stop_hook_active short-circuit — the first line of logic. Claude,
Gemini, and Codex set this snake_case field when the stop being evaluated
was already blocked once; the tentacle exits 0 before any dial or parsing
work. Claude additionally hard-caps 8 consecutive Stop blocks; Gemini and
Codex document no cap, which is why guard #2 exists.
One-shot marker — a mkdir-atomic marker directory under
$PD_HOME/squid/stop-blocks/ keyed by session id, with a TTL
(PD_SQUID_STOP_BLOCK_TTL_SECONDS, default 300 s). A session blocks at
most once per TTL window no matter what the vendor does. mkdir is the
lock — the same atomic-directory style the matrix writers use — so two
concurrent stops cannot both win the right to block.
Antigravity (agy) is observe-only: its camelCase Stop payload
(conversationId / workspacePaths / terminationReason / fullyIdle /
executionNum) carries no final-message field and no loop guard, its block
verb is a different dialect, and field reports say its Stop hooks may not
fire at all. The tentacle exits 0 on that shape unconditionally. Full
rationale: references/stop.md and references/vendor-matrix.md.
Known accepted miss: Claude Code's Stop does not fire on user interrupts,
so an interrupted turn is never SITREP-checked. SubagentStop exists on
Claude and Codex but is out of scope for the current tentacle (ADR-0092 L4's
adversarial-review pipeline is the follow-up).
The related SessionStart Pilot hook now adds a bounded, project-scoped salvage
count. Both nudges expose counts and corrective verbs only; message bodies and
salvage payloads stay in daemon truth until the agent explicitly runs
pd attention or pd salvage. Chapter 28 of the Agent Harbor binder owns the
larger lifecycle contract for Notification, SessionEnd, SubagentStop,
PreCompact, repository PR digests, and the future Postmaster role. Do not add
those as synchronous network-heavy tentacles: hooks emit bounded facts or
durable jobs, and expensive synthesis happens behind the daemon.
ADR ownership
ADR-0091 (docs/adr/0091-giant-squid-harness.md) maps "Drydock & Salvage"
to PreCompact/Stop for a future transcript-salvage tentacle
(pd-hook-compact, designed-not-built).
ADR-0092 (docs/adr/0092-suggestibility-ladder-and-cloud-coordination-federation.md)
defines L4 = Stop/SubagentStop as the closeout gate.
bin/pd-hook-stop implements ADR-0092 L4's closeout-gate half. It is
additive to ADR-0091's reservation: when pd-hook-compact lands, both hooks
can share the Stop event (vendors run every matching hook entry), so neither
ADR's decision text needed rewriting.
Registration checklist (adding or changing a tentacle)
A tentacle change is never just the script. The same-PR surface set:
lib/squid/hook-shape.ts — TENTACLES, REGISTERED_TENTACLES, the three
vendor event maps, buildJsonHookMap, codexHooksTomlBlock.
lib/squid/adapter.ts — SquidHookPurpose, SQUID_HOOK_METADATA
(displayName/description/privacy are byte-verified by the diagnose
functions), path-helper name unions, commandForPurpose, the diagnose
event maps, and all four injectHooks wanted maps.
cli/commands/hooks-install.ts — gate-wrapper phase case + breaker notice
label case (staging is generic over TENTACLES).
The doc-citation guard (scripts/check-doc-citations.mjs) fails a skill that
cites a tentacle path before it exists — tentacle + skill + registration ship
in ONE PR.
Test seams
Jest, not vitest: node --experimental-vm-modules node_modules/jest/bin/jest.js tests/unit/squid-harness.test.ts.
The harness suite pipes synthetic vendor payloads through the real shell
binaries — not mocks.
Dependency-free: scripts/squid-selftest.sh proves the same contracts
with zero node_modules (CI-portable, macOS/Linux).
Artifact boundary: scripts/smoke-squid-release.mjs arms every provider
from a staged release dir with the compiled pd — a source-suite pass never
substitutes for it.
Hermetic env: tests point PD_HOME / PD_MATRIX_FILE at scratch under
~/coding/tmp (never /tmp); the tentacles honor both.
jq-less coverage: every dial/extraction path needs a no-jq test (PATH
stripped to coreutils + python3) and, where behavior differs, a
no-parser-at-all test proving fail-open.
Quality gates
Tentacle passes sh -n and runs under dash without bashisms.
Every branch pipe-tested by hand: happy path, block path, loop guards,
each vendor payload shape, garbage stdin, empty stdin, missing jq.
Wall time comfortably under 250 ms (lib/squid/debug.ts:33).
All seven registration surfaces in the checklist above updated.