Skip to content

Commit df0ae6e

Browse files
cailmdaleyclaude
andcommitted
feat(hook): fully sever Portolan — read only the Shuttle event stream
The shuttle-hook is now live on all three hosts (~/loom/hooks/shuttle-hook.sh, registered by loom/setup.sh), so drop the Portolan fallback: default_events_file resolves only the Shuttle-owned path (SHUTTLE_EVENTS_FILE / $SHUTTLE_DATA_DIR / ~/.shuttle/events.jsonl). Removes portolan_events_file/0 + nonempty_file?/1. Docs: the waiting_tracker/sent_files bullet leaves the "still depends on Portolan" list; the event-stream section is present-tense (no fallback). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016RVNkdUCoxqgGVVhUoApVp
1 parent 3bf5e87 commit df0ae6e

2 files changed

Lines changed: 20 additions & 66 deletions

File tree

AGENTS.md

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,19 +30,6 @@ and Shuttle as one thing rather than two that shell to each other.
3030
Live runtime couplings (these silently break or no-op without Portolan, and are
3131
the real severing work):
3232

33-
- **`lib/shuttle/waiting_tracker.ex`** (and `sent_files.ex`, which delegates to
34-
its `default_events_file/0`) — read the Claude Code hook-event stream to derive
35-
per-session activity / "waiting" phase and the sent-files trail. **Shuttle now
36-
owns its own stream:** the readers prefer the Shuttle-owned path
37-
(`SHUTTLE_EVENTS_FILE`, else `$SHUTTLE_DATA_DIR/events.jsonl`, default
38-
`~/.shuttle/events.jsonl`, written by `~/loom/hooks/shuttle-hook.sh`) and **fall back**
39-
to the legacy Portolan path (`PORTOLAN_EVENTS_FILE` /
40-
`~/.portolan/data/events.jsonl`, written by `~/loom/hooks/portolan-hook.sh`)
41-
only when the Shuttle file is absent or empty. So behavior is unchanged until
42-
the Shuttle hook is installed (see "Owning the event stream" below), then it
43-
transparently switches. The event shape is identical, so the parsers are
44-
unchanged. Fully severing means dropping the Portolan fallback once the hook is
45-
installed everywhere.
4633
- **UI `:4004` backend (`ui/src/board/FiberDetailModal.ts`, `FileViewerPanel.ts`)**
4734
`portolanBase` defaults to `http://localhost:4004` and the standalone
4835
`KanbanModal` never overrides it, so **Sent-files**, **Save-to-downloads**, and
@@ -145,25 +132,22 @@ fragile and per-binary; relocating out of Documents is the supported fix.
145132
### Owning the event stream — `~/loom/hooks/shuttle-hook.sh`
146133

147134
Shuttle derives per-session activity (`WaitingTracker`) and the sent-files trail
148-
(`SentFiles`) from a Claude Code hook-event stream. `~/loom/hooks/shuttle-hook.sh`
135+
(`SentFiles`) from its OWN Claude Code hook-event stream. `~/loom/hooks/shuttle-hook.sh`
149136
appends one JSON line per hook event to `$SHUTTLE_EVENTS_FILE` (default
150-
`~/.shuttle/events.jsonl`, dir `$SHUTTLE_DATA_DIR`), in the same shape the legacy
151-
`portolan-hook.sh` writes, so the daemon no longer depends on Portolan's hook.
152-
Until the hook is registered on a machine, the readers fall back to Portolan's
153-
`~/.portolan/data/events.jsonl` there, so nothing breaks in the meantime.
154-
155-
**The hook lives in loom, registered by `loom/setup.sh` — exactly like
156-
portolan-hook.** The reason it can't live in this repo: `~/loom` is the same
157-
absolute path on every machine, but the shuttle checkout is not (`~/dev/shuttle`
158-
here, `~/Documents/projects/shuttle` on the clusters), and `~/.claude/settings.json`
159-
needs a stable absolute `command` path. `loom/setup.sh`'s Python block registers
160-
`~/loom/hooks/shuttle-hook.sh` into `~/.claude/settings.json` across the tracked
161-
events (UserPromptSubmit, PreToolUse, Stop, Notification, SessionStart, SessionEnd),
162-
*alongside* portolan-hook for now (both fire, write their own files; drop the
163-
portolan entries once Portolan is fully retired). To install on a machine: sync
164-
loom there, then run `~/loom/setup.sh`. The hook needs `jq` on PATH; without it it
165-
exits silently and the readers keep using the Portolan fallback. Each host's
166-
daemon tails its own host's `~/.shuttle/events.jsonl`.
137+
`~/.shuttle/events.jsonl`, dir `$SHUTTLE_DATA_DIR`). The readers read ONLY this
138+
path — the Portolan fallback was dropped once the hook was live on all three
139+
hosts; Portolan is fully severed here.
140+
141+
**The hook lives in loom, registered by `loom/setup.sh`.** It can't live in this
142+
repo: `~/loom` is the same absolute path on every machine, but the shuttle
143+
checkout is not (`~/dev/shuttle` here, `~/Documents/projects/shuttle` on the
144+
clusters), and `~/.claude/settings.json` needs a stable absolute `command` path.
145+
`loom/setup.sh`'s Python block registers `~/loom/hooks/shuttle-hook.sh` into
146+
`~/.claude/settings.json` across the tracked events (UserPromptSubmit, PreToolUse,
147+
Stop, Notification, SessionStart, SessionEnd). To install on a machine: sync loom
148+
there, then run `~/loom/setup.sh`. The hook needs `jq` on PATH; without it it
149+
exits silently (no events → no activity ranking, but the board still serves).
150+
Each host's daemon tails its own host's `~/.shuttle/events.jsonl`.
167151

168152
**Connecting to candide and cineca (SSH auth — read this first).** The two
169153
remotes authenticate differently, and getting it wrong looks like "the host is

lib/shuttle/waiting_tracker.ex

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -106,27 +106,13 @@ defmodule Shuttle.WaitingTracker do
106106
end
107107

108108
@doc """
109-
Default host-local events stream path, honoring the same env the hook reads.
110-
111-
Shuttle owns its own stream now: prefer the Shuttle-owned path
112-
(`SHUTTLE_EVENTS_FILE`, else `$SHUTTLE_DATA_DIR/events.jsonl`, default
113-
`~/.shuttle/events.jsonl` — written by `share/shuttle-hook.sh`). Fall back to
114-
the legacy Portolan path (`PORTOLAN_EVENTS_FILE` / `~/.portolan/data/events.jsonl`)
115-
when the Shuttle file is absent or empty, so behavior is unchanged until the
116-
Shuttle hook is installed, then it transparently switches.
109+
Default host-local events stream path, honoring the same env the hook writes.
110+
111+
Shuttle owns its own stream: `SHUTTLE_EVENTS_FILE`, else
112+
`$SHUTTLE_DATA_DIR/events.jsonl`, default `~/.shuttle/events.jsonl` — written by
113+
`~/loom/hooks/shuttle-hook.sh` (registered by `loom/setup.sh`).
117114
"""
118115
def default_events_file do
119-
shuttle = shuttle_events_file()
120-
121-
if nonempty_file?(shuttle) do
122-
shuttle
123-
else
124-
portolan = portolan_events_file()
125-
if nonempty_file?(portolan), do: portolan, else: shuttle
126-
end
127-
end
128-
129-
defp shuttle_events_file do
130116
System.get_env("SHUTTLE_EVENTS_FILE") ||
131117
Path.join(
132118
System.get_env("SHUTTLE_DATA_DIR") ||
@@ -135,22 +121,6 @@ defmodule Shuttle.WaitingTracker do
135121
)
136122
end
137123

138-
defp portolan_events_file do
139-
System.get_env("PORTOLAN_EVENTS_FILE") ||
140-
Path.join(
141-
System.get_env("PORTOLAN_DATA_DIR") ||
142-
Path.join(System.user_home!() || "/root", ".portolan/data"),
143-
"events.jsonl"
144-
)
145-
end
146-
147-
defp nonempty_file?(path) do
148-
case File.stat(path) do
149-
{:ok, %{size: size}} when size > 0 -> true
150-
_ -> false
151-
end
152-
end
153-
154124
# ── Server ──
155125

156126
@impl true

0 commit comments

Comments
 (0)