swarph-cli 0.10.2__tar.gz → 0.12.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {swarph_cli-0.10.2/src/swarph_cli.egg-info → swarph_cli-0.12.0}/PKG-INFO +65 -77
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/README.md +61 -73
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/pyproject.toml +4 -4
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/__init__.py +1 -1
- swarph_cli-0.12.0/src/swarph_cli/capture/__init__.py +6 -0
- swarph_cli-0.12.0/src/swarph_cli/capture/harden.py +140 -0
- swarph_cli-0.12.0/src/swarph_cli/capture/lineage.py +95 -0
- swarph_cli-0.12.0/src/swarph_cli/capture/liveness.py +69 -0
- swarph_cli-0.12.0/src/swarph_cli/capture/manifest.py +125 -0
- swarph_cli-0.12.0/src/swarph_cli/capture/paths.py +79 -0
- swarph_cli-0.12.0/src/swarph_cli/capture/verify.py +132 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/cell.py +42 -0
- swarph_cli-0.12.0/src/swarph_cli/commands/cell.py +83 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/onboard.py +9 -2
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/spawn.py +270 -8
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/main.py +1 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/systemd/swarph-watchdog.service +1 -1
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/systemd/swarph-watchdog.timer +1 -1
- {swarph_cli-0.10.2 → swarph_cli-0.12.0/src/swarph_cli.egg-info}/PKG-INFO +65 -77
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli.egg-info/SOURCES.txt +21 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_artifact_add.py +3 -1
- swarph_cli-0.12.0/tests/test_capture_lineage.py +81 -0
- swarph_cli-0.12.0/tests/test_capture_liveness.py +33 -0
- swarph_cli-0.12.0/tests/test_capture_manifest.py +83 -0
- swarph_cli-0.12.0/tests/test_capture_paths.py +15 -0
- swarph_cli-0.12.0/tests/test_capture_security.py +138 -0
- swarph_cli-0.12.0/tests/test_cell_command_dispatch.py +56 -0
- swarph_cli-0.12.0/tests/test_cell_harden.py +71 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_cell_loader.py +18 -0
- swarph_cli-0.12.0/tests/test_cell_verify.py +121 -0
- swarph_cli-0.12.0/tests/test_claude_tmux_template.py +54 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_hooks_add.py +5 -2
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_hooks_bundle.py +9 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_install_hook.py +8 -1
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_mcp_server.py +6 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_mesh_command.py +3 -1
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_onboard_command.py +9 -5
- swarph_cli-0.12.0/tests/test_session_path_role_gate.py +82 -0
- swarph_cli-0.12.0/tests/test_spawn_live_pin.py +44 -0
- swarph_cli-0.12.0/tests/test_spawn_mitosis_lineage.py +93 -0
- swarph_cli-0.12.0/tests/test_spawn_tmux_session.py +261 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_spawn_windows_relaunch.py +38 -3
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_watchdog.py +13 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_watchdog_model_rung.py +2 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/LICENSE +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/setup.cfg +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/caller.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/__init__.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/add.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/chat.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/compress.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/daemon.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/hook_output.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/hooks.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/import_session.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/init.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/install_hook.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/mcp_server.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/memory_sync.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/mesh.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/protocol_handler.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/ratify.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/security.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/commands/watchdog.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/compress/__init__.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/compress/levers.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/compress/marker.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/compress/verify.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/parsers/__init__.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/parsers/claude.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli/systemd/swarph-watchdog.default +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli.egg-info/dependency_links.txt +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli.egg-info/entry_points.txt +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli.egg-info/requires.txt +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/src/swarph_cli.egg-info/top_level.txt +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_add_security_gate.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_artifact_hash.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_artifact_lib.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_artifact_mcp.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_artifact_skill.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_artifact_tool.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_artifact_uri.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_chat_command.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_claude_parser.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_compress_command.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_compress_levers.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_compress_marker.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_compress_verify.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_daemon_command.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_feature_to_uri.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_hook_output.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_hooks_init.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_hooks_lifecycle.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_hooks_merge.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_import_command.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_init_command.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_main.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_memory_sync.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_mesh_sidecar.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_protocol_handler.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_ratify_command.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_security.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_smoke_chat.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_smoke_one_shot.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_smoke_phase_5_5.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_spawn_command.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_watchdog_dm_wake.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_watchdog_dm_wake_cooldown.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_watchdog_dm_wake_wiring.py +0 -0
- {swarph_cli-0.10.2 → swarph_cli-0.12.0}/tests/test_watchdog_stale_peers.py +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: swarph-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: The `swarph` binary — multi-LLM CLI + mesh-gateway integration: multi-provider `swarph spawn` (claude/codex/antigravity per cell.provider via a ProviderMembrane + subprocess billing-scrub), interactive `swarph init`, `swarph mesh` (send/inbox/register) + inbox sidecar, `assisted_memory` (git-backed durable memory), session import, watchdog. v0.9.5: foolproof Windows auto-relaunch (genuine-WT detection via process ancestry, not WT_SESSION).
|
|
5
5
|
Author: Pierre Samson, Claude Opus
|
|
6
6
|
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://github.com/
|
|
8
|
-
Project-URL: Source, https://github.com/
|
|
9
|
-
Project-URL: Substrate, https://github.com/
|
|
7
|
+
Project-URL: Homepage, https://github.com/BrainSurfing-tech/swarph-cli
|
|
8
|
+
Project-URL: Source, https://github.com/BrainSurfing-tech/swarph-cli
|
|
9
|
+
Project-URL: Substrate, https://github.com/BrainSurfing-tech/swarph-mesh
|
|
10
10
|
Project-URL: Spec, https://github.com/darw007d/hedge-fund-mcp/blob/main/research/swarph_cli/PLAN.md
|
|
11
11
|
Keywords: swarph,llm,cli,mesh,gemini,claude,deepseek
|
|
12
12
|
Classifier: Development Status :: 3 - Alpha
|
|
@@ -35,66 +35,72 @@ Dynamic: license-file
|
|
|
35
35
|
|
|
36
36
|
# swarph-cli
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
**One CLI for every LLM.** Drive Claude, GPT, Gemini, DeepSeek, and Grok from a single binary — then connect them into a coordinating *mesh* where agents from different vendors talk to each other through a shared protocol, each staying itself.
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
41
|
pip install swarph-cli
|
|
42
42
|
swarph --version
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
**What it is:** a multi-provider LLM command line. Run one-shot prompts or an interactive REPL against any supported provider; spawn long-lived agent *cells* that persist across restarts and coordinate over a mesh; install hooks, MCP servers, and skills by content-addressed URI. An open, inspectable substrate — not a closed orchestration platform.
|
|
46
|
+
|
|
47
|
+
**Who it's for:** builders running more than one LLM who want them to *cooperate* instead of sitting in separate tabs — multi-agent systems across vendors, agnostic by design. A thin client over the [`swarph-mesh`](https://github.com/BrainSurfing-tech/swarph-mesh) substrate library.
|
|
48
|
+
|
|
45
49
|
This is one of three repos in the v0.3.x architecture:
|
|
46
50
|
|
|
47
51
|
| Repo | Role |
|
|
48
52
|
|---|---|
|
|
49
|
-
| [`swarph-mesh`](https://github.com/
|
|
50
|
-
| [`swarph-cli`](https://github.com/
|
|
51
|
-
| [`swarph-meshlm`](https://github.com/
|
|
52
|
-
|
|
53
|
-
## Status
|
|
53
|
+
| [`swarph-mesh`](https://github.com/BrainSurfing-tech/swarph-mesh) | Substrate Python package — Protocol + adapters + SwarphCall + MeshClient. Pure library, no CLI |
|
|
54
|
+
| [`swarph-cli`](https://github.com/BrainSurfing-tech/swarph-cli) | This repo — the `swarph` binary |
|
|
55
|
+
| [`swarph-meshlm`](https://github.com/BrainSurfing-tech/swarph-meshlm) | Simon Willison `llm` plugin |
|
|
54
56
|
|
|
55
|
-
|
|
57
|
+
## Commands
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
```
|
|
60
|
+
swarph "prompt" one-shot against any provider (claude/openai/gemini/deepseek/grok)
|
|
61
|
+
swarph chat interactive REPL — multi-turn, slash commands, live provider switch
|
|
62
|
+
swarph spawn <role> launch a long-lived agent session as a named mesh cell
|
|
63
|
+
swarph daemon foreground inbox-drain loop (the mesh doorbell)
|
|
64
|
+
swarph watchdog detect + recover stranded agent sessions (cron- or systemd-driven)
|
|
65
|
+
swarph add <uri> install a hook / MCP server / skill by content-addressed URI
|
|
66
|
+
swarph hooks install Claude Code hooks as reusable artifacts
|
|
67
|
+
swarph onboard / ratify bring a new peer into the mesh (mechanics + witness ratification)
|
|
68
|
+
swarph import <path> port a session from another CLI into swarph-native format
|
|
69
|
+
```
|
|
64
70
|
|
|
65
|
-
|
|
71
|
+
Each verb is documented below.
|
|
66
72
|
|
|
67
73
|
### `swarph spawn` (Phase 7 — v0.6.0)
|
|
68
74
|
|
|
69
|
-
|
|
75
|
+
Wraps `claude` with three flags that make a session a stable, resumable named cell:
|
|
70
76
|
|
|
71
77
|
* `--name <role>` — display name for `/resume` picker
|
|
72
|
-
* `--session-id <uuid>` — pinned UUID, persisted to `$XDG_STATE_HOME/swarph/sessions/<role>.session-id` so re-spawns reuse the same session
|
|
73
|
-
* `--append-system-prompt <text>` — starter prompt injected without manual paste
|
|
78
|
+
* `--session-id <uuid>` — pinned UUID, persisted to `$XDG_STATE_HOME/swarph/sessions/<role>.session-id` so re-spawns reuse the same session
|
|
79
|
+
* `--append-system-prompt <text>` — starter prompt injected without manual paste
|
|
74
80
|
|
|
75
81
|
```bash
|
|
76
82
|
# 1. Author a cell.yaml (one-time per role)
|
|
77
|
-
$ cat ~/.config/swarph/cells/
|
|
83
|
+
$ cat ~/.config/swarph/cells/researcher.yaml
|
|
78
84
|
schema_version: v1
|
|
79
|
-
name:
|
|
80
|
-
role:
|
|
81
|
-
cwd:
|
|
85
|
+
name: researcher
|
|
86
|
+
role: researcher
|
|
87
|
+
cwd: ~/work
|
|
82
88
|
starter_prompt_path: ~/.claude/session_start_reminder.txt
|
|
83
89
|
provider: claude
|
|
84
90
|
|
|
85
91
|
# 2. Summon the cell (long-lived claude session, exec-replaced)
|
|
86
|
-
$ swarph spawn
|
|
92
|
+
$ swarph spawn researcher
|
|
87
93
|
╭───╮
|
|
88
94
|
│ ◉ │
|
|
89
95
|
╭──┴───┴──╮
|
|
90
|
-
│ swarph │
|
|
96
|
+
│ swarph │
|
|
91
97
|
╰──┬───┬──╯ spawn │ chat │ daemon
|
|
92
98
|
│ ◉ │
|
|
93
99
|
╰───╯
|
|
94
|
-
[claude session takes over the terminal — same flags as `claude --name
|
|
100
|
+
[claude session takes over the terminal — same flags as `claude --name researcher --session-id <uuid> --append-system-prompt <starter>`]
|
|
95
101
|
|
|
96
102
|
# 3. Resume the same cell after exit — same UUID, same session
|
|
97
|
-
$ swarph spawn
|
|
103
|
+
$ swarph spawn researcher # picker shows ONE entry: "researcher" (stable disambiguation)
|
|
98
104
|
```
|
|
99
105
|
|
|
100
106
|
Resolution order for `swarph spawn <role-or-path>`:
|
|
@@ -127,16 +133,16 @@ ps aux | grep '[s]warph daemon' # zero output = monitoring is down
|
|
|
127
133
|
```
|
|
128
134
|
|
|
129
135
|
```bash
|
|
130
|
-
$ swarph daemon --state-dir ~/swarph_state/
|
|
131
|
-
[swarph-daemon] starting: self=
|
|
132
|
-
[2026-05-08T21:00:30Z] id=728 from=
|
|
133
|
-
[2026-05-08T21:01:10Z] id=729 from=
|
|
136
|
+
$ swarph daemon --state-dir ~/swarph_state/researcher --self researcher
|
|
137
|
+
[swarph-daemon] starting: self=researcher gateway=http://localhost:8788 poll=30s ...
|
|
138
|
+
[2026-05-08T21:00:30Z] id=728 from=alice kind=answer → 'review on the two PRs looks good...'
|
|
139
|
+
[2026-05-08T21:01:10Z] id=729 from=alice kind=fyi → 'both PRs merged...'
|
|
134
140
|
^C
|
|
135
141
|
[swarph-daemon] signal 2 received — draining + flushing cursor
|
|
136
142
|
[swarph-daemon] shutdown: iterations=12 dms_seen=2 cursor.last_msg_id=729
|
|
137
143
|
```
|
|
138
144
|
|
|
139
|
-
Loud-on-down
|
|
145
|
+
Loud-on-down: never silently exits. Cursor writes are atomic (write-and-rename — corrupted mid-flush leaves the previous cursor intact). Backoff: 60s after 5 consecutive empty polls; 300s after 5 min of consecutive 5xx. SIGINT/SIGTERM trigger clean drain + flush.
|
|
140
146
|
|
|
141
147
|
`--auto-act` flag is documented for v0.5.1+ when handler registration via `@swarph.on_dm(...)` lands; v0.5.0 ships surface-only mode (DMs printed + JSONL-logged to `inbox.log`, no automatic replies).
|
|
142
148
|
|
|
@@ -149,14 +155,14 @@ Detects stranded Claude sessions (API throttle / harness death) via cursor-mtime
|
|
|
149
155
|
*/5 * * * * swarph watchdog --check --cell lab >> ~/.local/log/swarph-watchdog.log 2>&1
|
|
150
156
|
```
|
|
151
157
|
|
|
152
|
-
**Systemd timer install (v0.7.3+
|
|
158
|
+
**Systemd timer install (v0.7.3+):**
|
|
153
159
|
|
|
154
160
|
```bash
|
|
155
161
|
# Preview without writing (any user):
|
|
156
|
-
swarph watchdog --install-service --cell
|
|
162
|
+
swarph watchdog --install-service --cell researcher --dry-run
|
|
157
163
|
|
|
158
164
|
# Install + enable (requires root for /etc/systemd/system writes):
|
|
159
|
-
sudo swarph watchdog --install-service --cell
|
|
165
|
+
sudo swarph watchdog --install-service --cell researcher
|
|
160
166
|
```
|
|
161
167
|
|
|
162
168
|
This writes three files:
|
|
@@ -178,19 +184,19 @@ journalctl -u swarph-watchdog.service -f # live log
|
|
|
178
184
|
tail -f /var/log/swarph-watchdog.log # append-log alternative
|
|
179
185
|
```
|
|
180
186
|
|
|
181
|
-
Why this matters:
|
|
187
|
+
Why this matters: a long-running agent session can go silent after an API throttle or a harness death, and you won't notice until you go looking. The watchdog turns that into a self-healing loop — and the systemd install path means any host gets it with one command instead of hand-rolled cron.
|
|
182
188
|
|
|
183
189
|
**Cross-host throttle-recovery wake (`--dm-wake`, "mesh-monitor mode"):**
|
|
184
190
|
|
|
185
191
|
A1 (local tmux send-keys) and A2 (respawn) can only recover a cell on the watchdog's *own* host. `--dm-wake` adds the cross-host complement: the watchdog also scans the gateway `/peers` list, finds peers whose `last_health` is stale (throttle-stranded sessions on *other* hosts), and sends each a wake DM (`kind="fyi"`) via the gateway `/messages`. The wake chain is **watchdog → wake DM → target peer's sidecar/inbox-watcher → `tmux send-keys` wakes that session**. Reuses the same `--gateway` URL + `MESH_GATEWAY_TOKEN` and the same `--threshold` staleness window as the local check.
|
|
186
192
|
|
|
187
193
|
```bash
|
|
188
|
-
swarph watchdog --check --peer
|
|
194
|
+
swarph watchdog --check --peer researcher --gateway http://localhost:8788 --dm-wake --dm-wake-cooldown-sec 1800
|
|
189
195
|
```
|
|
190
196
|
|
|
191
197
|
- `--dm-wake-cooldown-sec SEC` (default `1800` / 30 min) — no-spam gate: each stale peer is DM-woken at most once per window, so a peer that stays stale across many ticks is woken once, not every tick. Per-peer cooldown state lives at `$XDG_STATE_HOME/swarph/dm_wake_state.json` (falls back to `~/.local/state/swarph/dm_wake_state.json`).
|
|
192
198
|
|
|
193
|
-
**Scope honesty (v1):** the wake DM is *wake + re-drain* — the woken cell drains its inbox and resumes work; it does **not** resume the exact throttled in-flight task (per-cell task-checkpointing is future
|
|
199
|
+
**Scope honesty (v1):** the wake DM is *wake + re-drain* — the woken cell drains its inbox and resumes work; it does **not** resume the exact throttled in-flight task (per-cell task-checkpointing is future scope).
|
|
194
200
|
|
|
195
201
|
**Exit codes:**
|
|
196
202
|
|
|
@@ -203,7 +209,7 @@ swarph watchdog --check --peer lab-ovh --gateway http://localhost:8788 --dm-wake
|
|
|
203
209
|
| `4` | configuration error (invalid args, no cell.yaml resolved); install needs sudo |
|
|
204
210
|
| `5` | install error (file write failed / systemctl failed) |
|
|
205
211
|
|
|
206
|
-
**Deploy
|
|
212
|
+
**Deploy:** run `--dm-wake` on whichever always-on host you want to act as the mesh monitor — it watches every peer's health, not just its own, so one monitor covers the mesh.
|
|
207
213
|
|
|
208
214
|
### `swarph hooks`
|
|
209
215
|
|
|
@@ -217,7 +223,7 @@ swarph hooks list # builtins + install status (installed|availab
|
|
|
217
223
|
swarph hooks remove cell-resilience
|
|
218
224
|
```
|
|
219
225
|
|
|
220
|
-
**Trust model.** Three tiers: `builtin` (trusted, bundled with swarph-cli — installs without a prompt), `local` (a bundle dir you point at — shown then confirmed before any write), and `published`/`@cell/name` (**fails closed in v1** — never installs another cell's unreviewed code). Signed-publisher identity plus a publish-time security gate is the v2 model
|
|
226
|
+
**Trust model.** Three tiers: `builtin` (trusted, bundled with swarph-cli — installs without a prompt), `local` (a bundle dir you point at — shown then confirmed before any write), and `published`/`@cell/name` (**fails closed in v1** — never installs another cell's unreviewed code). Signed-publisher identity plus a publish-time security gate is the v2 model.
|
|
221
227
|
|
|
222
228
|
**Bundled `cell-resilience`.** Binds `StopFailure`/`rate_limit` + `Stop`/`(all)` to a script that writes `$XDG_STATE_HOME/swarph/idle_since.json` (`{"session","reason","hook_event","ts"}`, `reason=throttle|normal`) — the push-side throttle detector the watchdog's `--dm-wake` can read instead of polling. Observational only: it never blocks the session and always exits 0 (jq if present, printf/sed fallback otherwise).
|
|
223
229
|
|
|
@@ -237,36 +243,36 @@ swarph add swarph://skill/swarph-builtin/swarph-intro # install a builtin sk
|
|
|
237
243
|
|
|
238
244
|
(`tool` is not yet implemented — it bridges to swarph-mesh's adapter registry as a follow-on.)
|
|
239
245
|
|
|
240
|
-
**Trust model (v1).** Builtin publishers (`swarph-builtin`) install; **any other publisher fails closed** — a published/untrusted URI never installs another cell's unreviewed code. Signed-publisher identity plus a per-class publish-time security gate is the v2 model
|
|
246
|
+
**Trust model (v1).** Builtin publishers (`swarph-builtin`) install; **any other publisher fails closed** — a published/untrusted URI never installs another cell's unreviewed code. Signed-publisher identity plus a per-class publish-time security gate is the v2 model. When a URI carries `#sha256`, the resolved artifact is hash-verified and **refused on mismatch** — nothing is written.
|
|
241
247
|
|
|
242
|
-
**
|
|
248
|
+
**Content-addressed, not host-addressed.** A `swarph://` URI resolves *to the artifact*, not to a particular server: the CLI fetches it from any cell or registry that publishes it and hash-verifies against `#sha256`, so the same artifact can be served from anywhere — the BitTorrent-magnet property. Today the URI is copy-paste; a `swarph://` OS protocol-handler for click-to-install — the way `magnet:` opens a torrent client — is a future UX layer.
|
|
243
249
|
|
|
244
250
|
**Activation.** Like hooks, freshly-installed hooks and skills are not hot-loaded into the running session — reopen `/hooks` (or restart the session) once to pick them up.
|
|
245
251
|
|
|
246
252
|
### `swarph onboard` + `swarph ratify` (Phase 5.5)
|
|
247
253
|
|
|
248
|
-
|
|
254
|
+
Onboarding splits into a **mechanics phase** (`swarph onboard`) that automates the boring parts (registry POST, scaffolding, token resolution) and a **manual contract phase** (the new peer composes the handshake DM in their own words). A witness peer judges the handshake and runs `swarph ratify <peer>` to flip `ratified=true`, gating `task_claim` server-side.
|
|
249
255
|
|
|
250
256
|
```bash
|
|
251
257
|
# New peer self-onboards
|
|
252
|
-
$ swarph onboard
|
|
253
|
-
[1/6] validate_node_name('
|
|
258
|
+
$ swarph onboard newpeer
|
|
259
|
+
[1/6] validate_node_name('newpeer') ok
|
|
254
260
|
[2/6] prepare peer-registry row ok
|
|
255
261
|
[3/6] resolve MESH_GATEWAY_TOKEN ok
|
|
256
262
|
[4/6] POST .../peers/register ok (registered_unratified=true)
|
|
257
263
|
[5/6] verify_subscription_setup() ok
|
|
258
|
-
[6/6] scaffold ~/swarph_state/
|
|
264
|
+
[6/6] scaffold ~/swarph_state/newpeer/ ok
|
|
259
265
|
|
|
260
|
-
[manual] handshake template at /tmp/
|
|
266
|
+
[manual] handshake template at /tmp/newpeer-handshake.md
|
|
261
267
|
Edit each section in your own words, then send to your witness peer.
|
|
262
268
|
|
|
263
269
|
# After peer composes + sends handshake, witness ratifies
|
|
264
|
-
$ SWARPH_WITNESS=
|
|
270
|
+
$ SWARPH_WITNESS=alice swarph ratify newpeer \
|
|
265
271
|
--reason "handshake covers all four invariants in own words"
|
|
266
|
-
[1/6] validate_node_name('
|
|
267
|
-
[2/6] verify witness '
|
|
268
|
-
[3/6] verify '
|
|
269
|
-
[4/6] PATCH .../peers/
|
|
272
|
+
[1/6] validate_node_name('newpeer') ok
|
|
273
|
+
[2/6] verify witness 'alice' is ratified ok
|
|
274
|
+
[3/6] verify 'newpeer' is registered_unratified ok
|
|
275
|
+
[4/6] PATCH .../peers/newpeer ok
|
|
270
276
|
[5/6] verify peer_ratifications audit row ok (id=N reason='...')
|
|
271
277
|
[6/6] invalidate local TTL cache ok
|
|
272
278
|
```
|
|
@@ -314,7 +320,7 @@ Hi! How can I help...
|
|
|
314
320
|
|
|
315
321
|
### `swarph import`
|
|
316
322
|
|
|
317
|
-
|
|
323
|
+
Session import is the **knowledge half of onboarding** — gives a memory-carrying peer (or a human migrating between CLIs) the substantive context they're bringing into the swarph, paired with the contract half (the handshake DM acknowledging the four invariants).
|
|
318
324
|
|
|
319
325
|
```bash
|
|
320
326
|
# Inspect what would be imported (lossy → honest framing)
|
|
@@ -340,7 +346,7 @@ To proceed:
|
|
|
340
346
|
|
|
341
347
|
**What's dropped:** attachments (would need re-upload), provider-side KV cache, conversation IDs, `cache_control` annotations.
|
|
342
348
|
|
|
343
|
-
Honest framing
|
|
349
|
+
Honest framing: **teleport is "import + continue", not "freeze and resume"** — the first turn after import on a new provider pays cold-cache cost.
|
|
344
350
|
|
|
345
351
|
```bash
|
|
346
352
|
$ swarph "say pong" --provider gemini
|
|
@@ -415,32 +421,14 @@ Design spec: `docs/superpowers/specs/2026-06-11-swarph-context-compressor-design
|
|
|
415
421
|
```
|
|
416
422
|
- Pretty-printed parsed dict on stdout when parse succeeds; `error_class=malformed_json` shows up in the stderr attribution footer when it doesn't.
|
|
417
423
|
|
|
418
|
-
## Spec
|
|
419
|
-
|
|
420
|
-
→ [hedge-fund-mcp / research/swarph_cli/PLAN.md](https://github.com/darw007d/hedge-fund-mcp/blob/main/research/swarph_cli/PLAN.md)
|
|
421
|
-
|
|
422
|
-
## Phase rollout
|
|
423
|
-
|
|
424
|
-
| Phase | What lands |
|
|
425
|
-
|---|---|
|
|
426
|
-
| **0** | Scaffold — entry-point + status banner |
|
|
427
|
-
| **2** (v0.1.0) | One-shot mode: `swarph "hello" --provider gemini` |
|
|
428
|
-
| **2.5** (v0.2.0) | `swarph import` — Claude JSONL → swarph-native session format |
|
|
429
|
-
| **5** (v0.3.0) | `swarph chat` interactive REPL — multi-turn against any of five adapters + slash commands |
|
|
430
|
-
| **5.5** (v0.4.0) | `swarph onboard` + `swarph ratify` — six mechanics steps + handshake template + witness flip (PLAN.md §15) |
|
|
431
|
-
| **5.6** (v0.5.0 — this release) | **`swarph daemon`** — foreground inbox drain loop with atomic cursor writes; retires the orphaned-tail-F class (PLAN.md §16) |
|
|
432
|
-
| **5.6b** | REPL drain coroutine + `/inbox`/`/reply` slash commands + `@swarph.on_dm()` handler registration (mesh + cli) |
|
|
433
|
-
| **3** | `--ask <peer>` mesh-aware one-shot via MeshClient |
|
|
434
|
-
| **6** | (already done) PyPI publish |
|
|
435
|
-
|
|
436
424
|
## Why split CLI from substrate
|
|
437
425
|
|
|
438
|
-
`swarph-mesh`
|
|
426
|
+
The [`swarph-mesh`](https://github.com/BrainSurfing-tech/swarph-mesh) library is imported by any program that wants to drive the mesh against the Protocol directly — orchestrators, judges, automation. Those callers don't need the CLI surface or the console-script entry point. Keeping the CLI in a separate repo means library users `pip install swarph-mesh` without pulling argparse + REPL plumbing they'll never run, while `pip install swarph-cli` gives you the standalone `swarph` binary.
|
|
439
427
|
|
|
440
428
|
## Install (dev)
|
|
441
429
|
|
|
442
430
|
```bash
|
|
443
|
-
git clone https://github.com/
|
|
431
|
+
git clone https://github.com/BrainSurfing-tech/swarph-cli
|
|
444
432
|
cd swarph-cli
|
|
445
433
|
python -m venv venv && source venv/bin/activate
|
|
446
434
|
pip install -e ".[dev]"
|
|
@@ -1,65 +1,71 @@
|
|
|
1
1
|
# swarph-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
**One CLI for every LLM.** Drive Claude, GPT, Gemini, DeepSeek, and Grok from a single binary — then connect them into a coordinating *mesh* where agents from different vendors talk to each other through a shared protocol, each staying itself.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
pip install swarph-cli
|
|
7
7
|
swarph --version
|
|
8
8
|
```
|
|
9
9
|
|
|
10
|
+
**What it is:** a multi-provider LLM command line. Run one-shot prompts or an interactive REPL against any supported provider; spawn long-lived agent *cells* that persist across restarts and coordinate over a mesh; install hooks, MCP servers, and skills by content-addressed URI. An open, inspectable substrate — not a closed orchestration platform.
|
|
11
|
+
|
|
12
|
+
**Who it's for:** builders running more than one LLM who want them to *cooperate* instead of sitting in separate tabs — multi-agent systems across vendors, agnostic by design. A thin client over the [`swarph-mesh`](https://github.com/BrainSurfing-tech/swarph-mesh) substrate library.
|
|
13
|
+
|
|
10
14
|
This is one of three repos in the v0.3.x architecture:
|
|
11
15
|
|
|
12
16
|
| Repo | Role |
|
|
13
17
|
|---|---|
|
|
14
|
-
| [`swarph-mesh`](https://github.com/
|
|
15
|
-
| [`swarph-cli`](https://github.com/
|
|
16
|
-
| [`swarph-meshlm`](https://github.com/
|
|
17
|
-
|
|
18
|
-
## Status
|
|
18
|
+
| [`swarph-mesh`](https://github.com/BrainSurfing-tech/swarph-mesh) | Substrate Python package — Protocol + adapters + SwarphCall + MeshClient. Pure library, no CLI |
|
|
19
|
+
| [`swarph-cli`](https://github.com/BrainSurfing-tech/swarph-cli) | This repo — the `swarph` binary |
|
|
20
|
+
| [`swarph-meshlm`](https://github.com/BrainSurfing-tech/swarph-meshlm) | Simon Willison `llm` plugin |
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
## Commands
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
```
|
|
25
|
+
swarph "prompt" one-shot against any provider (claude/openai/gemini/deepseek/grok)
|
|
26
|
+
swarph chat interactive REPL — multi-turn, slash commands, live provider switch
|
|
27
|
+
swarph spawn <role> launch a long-lived agent session as a named mesh cell
|
|
28
|
+
swarph daemon foreground inbox-drain loop (the mesh doorbell)
|
|
29
|
+
swarph watchdog detect + recover stranded agent sessions (cron- or systemd-driven)
|
|
30
|
+
swarph add <uri> install a hook / MCP server / skill by content-addressed URI
|
|
31
|
+
swarph hooks install Claude Code hooks as reusable artifacts
|
|
32
|
+
swarph onboard / ratify bring a new peer into the mesh (mechanics + witness ratification)
|
|
33
|
+
swarph import <path> port a session from another CLI into swarph-native format
|
|
34
|
+
```
|
|
29
35
|
|
|
30
|
-
|
|
36
|
+
Each verb is documented below.
|
|
31
37
|
|
|
32
38
|
### `swarph spawn` (Phase 7 — v0.6.0)
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
Wraps `claude` with three flags that make a session a stable, resumable named cell:
|
|
35
41
|
|
|
36
42
|
* `--name <role>` — display name for `/resume` picker
|
|
37
|
-
* `--session-id <uuid>` — pinned UUID, persisted to `$XDG_STATE_HOME/swarph/sessions/<role>.session-id` so re-spawns reuse the same session
|
|
38
|
-
* `--append-system-prompt <text>` — starter prompt injected without manual paste
|
|
43
|
+
* `--session-id <uuid>` — pinned UUID, persisted to `$XDG_STATE_HOME/swarph/sessions/<role>.session-id` so re-spawns reuse the same session
|
|
44
|
+
* `--append-system-prompt <text>` — starter prompt injected without manual paste
|
|
39
45
|
|
|
40
46
|
```bash
|
|
41
47
|
# 1. Author a cell.yaml (one-time per role)
|
|
42
|
-
$ cat ~/.config/swarph/cells/
|
|
48
|
+
$ cat ~/.config/swarph/cells/researcher.yaml
|
|
43
49
|
schema_version: v1
|
|
44
|
-
name:
|
|
45
|
-
role:
|
|
46
|
-
cwd:
|
|
50
|
+
name: researcher
|
|
51
|
+
role: researcher
|
|
52
|
+
cwd: ~/work
|
|
47
53
|
starter_prompt_path: ~/.claude/session_start_reminder.txt
|
|
48
54
|
provider: claude
|
|
49
55
|
|
|
50
56
|
# 2. Summon the cell (long-lived claude session, exec-replaced)
|
|
51
|
-
$ swarph spawn
|
|
57
|
+
$ swarph spawn researcher
|
|
52
58
|
╭───╮
|
|
53
59
|
│ ◉ │
|
|
54
60
|
╭──┴───┴──╮
|
|
55
|
-
│ swarph │
|
|
61
|
+
│ swarph │
|
|
56
62
|
╰──┬───┬──╯ spawn │ chat │ daemon
|
|
57
63
|
│ ◉ │
|
|
58
64
|
╰───╯
|
|
59
|
-
[claude session takes over the terminal — same flags as `claude --name
|
|
65
|
+
[claude session takes over the terminal — same flags as `claude --name researcher --session-id <uuid> --append-system-prompt <starter>`]
|
|
60
66
|
|
|
61
67
|
# 3. Resume the same cell after exit — same UUID, same session
|
|
62
|
-
$ swarph spawn
|
|
68
|
+
$ swarph spawn researcher # picker shows ONE entry: "researcher" (stable disambiguation)
|
|
63
69
|
```
|
|
64
70
|
|
|
65
71
|
Resolution order for `swarph spawn <role-or-path>`:
|
|
@@ -92,16 +98,16 @@ ps aux | grep '[s]warph daemon' # zero output = monitoring is down
|
|
|
92
98
|
```
|
|
93
99
|
|
|
94
100
|
```bash
|
|
95
|
-
$ swarph daemon --state-dir ~/swarph_state/
|
|
96
|
-
[swarph-daemon] starting: self=
|
|
97
|
-
[2026-05-08T21:00:30Z] id=728 from=
|
|
98
|
-
[2026-05-08T21:01:10Z] id=729 from=
|
|
101
|
+
$ swarph daemon --state-dir ~/swarph_state/researcher --self researcher
|
|
102
|
+
[swarph-daemon] starting: self=researcher gateway=http://localhost:8788 poll=30s ...
|
|
103
|
+
[2026-05-08T21:00:30Z] id=728 from=alice kind=answer → 'review on the two PRs looks good...'
|
|
104
|
+
[2026-05-08T21:01:10Z] id=729 from=alice kind=fyi → 'both PRs merged...'
|
|
99
105
|
^C
|
|
100
106
|
[swarph-daemon] signal 2 received — draining + flushing cursor
|
|
101
107
|
[swarph-daemon] shutdown: iterations=12 dms_seen=2 cursor.last_msg_id=729
|
|
102
108
|
```
|
|
103
109
|
|
|
104
|
-
Loud-on-down
|
|
110
|
+
Loud-on-down: never silently exits. Cursor writes are atomic (write-and-rename — corrupted mid-flush leaves the previous cursor intact). Backoff: 60s after 5 consecutive empty polls; 300s after 5 min of consecutive 5xx. SIGINT/SIGTERM trigger clean drain + flush.
|
|
105
111
|
|
|
106
112
|
`--auto-act` flag is documented for v0.5.1+ when handler registration via `@swarph.on_dm(...)` lands; v0.5.0 ships surface-only mode (DMs printed + JSONL-logged to `inbox.log`, no automatic replies).
|
|
107
113
|
|
|
@@ -114,14 +120,14 @@ Detects stranded Claude sessions (API throttle / harness death) via cursor-mtime
|
|
|
114
120
|
*/5 * * * * swarph watchdog --check --cell lab >> ~/.local/log/swarph-watchdog.log 2>&1
|
|
115
121
|
```
|
|
116
122
|
|
|
117
|
-
**Systemd timer install (v0.7.3+
|
|
123
|
+
**Systemd timer install (v0.7.3+):**
|
|
118
124
|
|
|
119
125
|
```bash
|
|
120
126
|
# Preview without writing (any user):
|
|
121
|
-
swarph watchdog --install-service --cell
|
|
127
|
+
swarph watchdog --install-service --cell researcher --dry-run
|
|
122
128
|
|
|
123
129
|
# Install + enable (requires root for /etc/systemd/system writes):
|
|
124
|
-
sudo swarph watchdog --install-service --cell
|
|
130
|
+
sudo swarph watchdog --install-service --cell researcher
|
|
125
131
|
```
|
|
126
132
|
|
|
127
133
|
This writes three files:
|
|
@@ -143,19 +149,19 @@ journalctl -u swarph-watchdog.service -f # live log
|
|
|
143
149
|
tail -f /var/log/swarph-watchdog.log # append-log alternative
|
|
144
150
|
```
|
|
145
151
|
|
|
146
|
-
Why this matters:
|
|
152
|
+
Why this matters: a long-running agent session can go silent after an API throttle or a harness death, and you won't notice until you go looking. The watchdog turns that into a self-healing loop — and the systemd install path means any host gets it with one command instead of hand-rolled cron.
|
|
147
153
|
|
|
148
154
|
**Cross-host throttle-recovery wake (`--dm-wake`, "mesh-monitor mode"):**
|
|
149
155
|
|
|
150
156
|
A1 (local tmux send-keys) and A2 (respawn) can only recover a cell on the watchdog's *own* host. `--dm-wake` adds the cross-host complement: the watchdog also scans the gateway `/peers` list, finds peers whose `last_health` is stale (throttle-stranded sessions on *other* hosts), and sends each a wake DM (`kind="fyi"`) via the gateway `/messages`. The wake chain is **watchdog → wake DM → target peer's sidecar/inbox-watcher → `tmux send-keys` wakes that session**. Reuses the same `--gateway` URL + `MESH_GATEWAY_TOKEN` and the same `--threshold` staleness window as the local check.
|
|
151
157
|
|
|
152
158
|
```bash
|
|
153
|
-
swarph watchdog --check --peer
|
|
159
|
+
swarph watchdog --check --peer researcher --gateway http://localhost:8788 --dm-wake --dm-wake-cooldown-sec 1800
|
|
154
160
|
```
|
|
155
161
|
|
|
156
162
|
- `--dm-wake-cooldown-sec SEC` (default `1800` / 30 min) — no-spam gate: each stale peer is DM-woken at most once per window, so a peer that stays stale across many ticks is woken once, not every tick. Per-peer cooldown state lives at `$XDG_STATE_HOME/swarph/dm_wake_state.json` (falls back to `~/.local/state/swarph/dm_wake_state.json`).
|
|
157
163
|
|
|
158
|
-
**Scope honesty (v1):** the wake DM is *wake + re-drain* — the woken cell drains its inbox and resumes work; it does **not** resume the exact throttled in-flight task (per-cell task-checkpointing is future
|
|
164
|
+
**Scope honesty (v1):** the wake DM is *wake + re-drain* — the woken cell drains its inbox and resumes work; it does **not** resume the exact throttled in-flight task (per-cell task-checkpointing is future scope).
|
|
159
165
|
|
|
160
166
|
**Exit codes:**
|
|
161
167
|
|
|
@@ -168,7 +174,7 @@ swarph watchdog --check --peer lab-ovh --gateway http://localhost:8788 --dm-wake
|
|
|
168
174
|
| `4` | configuration error (invalid args, no cell.yaml resolved); install needs sudo |
|
|
169
175
|
| `5` | install error (file write failed / systemctl failed) |
|
|
170
176
|
|
|
171
|
-
**Deploy
|
|
177
|
+
**Deploy:** run `--dm-wake` on whichever always-on host you want to act as the mesh monitor — it watches every peer's health, not just its own, so one monitor covers the mesh.
|
|
172
178
|
|
|
173
179
|
### `swarph hooks`
|
|
174
180
|
|
|
@@ -182,7 +188,7 @@ swarph hooks list # builtins + install status (installed|availab
|
|
|
182
188
|
swarph hooks remove cell-resilience
|
|
183
189
|
```
|
|
184
190
|
|
|
185
|
-
**Trust model.** Three tiers: `builtin` (trusted, bundled with swarph-cli — installs without a prompt), `local` (a bundle dir you point at — shown then confirmed before any write), and `published`/`@cell/name` (**fails closed in v1** — never installs another cell's unreviewed code). Signed-publisher identity plus a publish-time security gate is the v2 model
|
|
191
|
+
**Trust model.** Three tiers: `builtin` (trusted, bundled with swarph-cli — installs without a prompt), `local` (a bundle dir you point at — shown then confirmed before any write), and `published`/`@cell/name` (**fails closed in v1** — never installs another cell's unreviewed code). Signed-publisher identity plus a publish-time security gate is the v2 model.
|
|
186
192
|
|
|
187
193
|
**Bundled `cell-resilience`.** Binds `StopFailure`/`rate_limit` + `Stop`/`(all)` to a script that writes `$XDG_STATE_HOME/swarph/idle_since.json` (`{"session","reason","hook_event","ts"}`, `reason=throttle|normal`) — the push-side throttle detector the watchdog's `--dm-wake` can read instead of polling. Observational only: it never blocks the session and always exits 0 (jq if present, printf/sed fallback otherwise).
|
|
188
194
|
|
|
@@ -202,36 +208,36 @@ swarph add swarph://skill/swarph-builtin/swarph-intro # install a builtin sk
|
|
|
202
208
|
|
|
203
209
|
(`tool` is not yet implemented — it bridges to swarph-mesh's adapter registry as a follow-on.)
|
|
204
210
|
|
|
205
|
-
**Trust model (v1).** Builtin publishers (`swarph-builtin`) install; **any other publisher fails closed** — a published/untrusted URI never installs another cell's unreviewed code. Signed-publisher identity plus a per-class publish-time security gate is the v2 model
|
|
211
|
+
**Trust model (v1).** Builtin publishers (`swarph-builtin`) install; **any other publisher fails closed** — a published/untrusted URI never installs another cell's unreviewed code. Signed-publisher identity plus a per-class publish-time security gate is the v2 model. When a URI carries `#sha256`, the resolved artifact is hash-verified and **refused on mismatch** — nothing is written.
|
|
206
212
|
|
|
207
|
-
**
|
|
213
|
+
**Content-addressed, not host-addressed.** A `swarph://` URI resolves *to the artifact*, not to a particular server: the CLI fetches it from any cell or registry that publishes it and hash-verifies against `#sha256`, so the same artifact can be served from anywhere — the BitTorrent-magnet property. Today the URI is copy-paste; a `swarph://` OS protocol-handler for click-to-install — the way `magnet:` opens a torrent client — is a future UX layer.
|
|
208
214
|
|
|
209
215
|
**Activation.** Like hooks, freshly-installed hooks and skills are not hot-loaded into the running session — reopen `/hooks` (or restart the session) once to pick them up.
|
|
210
216
|
|
|
211
217
|
### `swarph onboard` + `swarph ratify` (Phase 5.5)
|
|
212
218
|
|
|
213
|
-
|
|
219
|
+
Onboarding splits into a **mechanics phase** (`swarph onboard`) that automates the boring parts (registry POST, scaffolding, token resolution) and a **manual contract phase** (the new peer composes the handshake DM in their own words). A witness peer judges the handshake and runs `swarph ratify <peer>` to flip `ratified=true`, gating `task_claim` server-side.
|
|
214
220
|
|
|
215
221
|
```bash
|
|
216
222
|
# New peer self-onboards
|
|
217
|
-
$ swarph onboard
|
|
218
|
-
[1/6] validate_node_name('
|
|
223
|
+
$ swarph onboard newpeer
|
|
224
|
+
[1/6] validate_node_name('newpeer') ok
|
|
219
225
|
[2/6] prepare peer-registry row ok
|
|
220
226
|
[3/6] resolve MESH_GATEWAY_TOKEN ok
|
|
221
227
|
[4/6] POST .../peers/register ok (registered_unratified=true)
|
|
222
228
|
[5/6] verify_subscription_setup() ok
|
|
223
|
-
[6/6] scaffold ~/swarph_state/
|
|
229
|
+
[6/6] scaffold ~/swarph_state/newpeer/ ok
|
|
224
230
|
|
|
225
|
-
[manual] handshake template at /tmp/
|
|
231
|
+
[manual] handshake template at /tmp/newpeer-handshake.md
|
|
226
232
|
Edit each section in your own words, then send to your witness peer.
|
|
227
233
|
|
|
228
234
|
# After peer composes + sends handshake, witness ratifies
|
|
229
|
-
$ SWARPH_WITNESS=
|
|
235
|
+
$ SWARPH_WITNESS=alice swarph ratify newpeer \
|
|
230
236
|
--reason "handshake covers all four invariants in own words"
|
|
231
|
-
[1/6] validate_node_name('
|
|
232
|
-
[2/6] verify witness '
|
|
233
|
-
[3/6] verify '
|
|
234
|
-
[4/6] PATCH .../peers/
|
|
237
|
+
[1/6] validate_node_name('newpeer') ok
|
|
238
|
+
[2/6] verify witness 'alice' is ratified ok
|
|
239
|
+
[3/6] verify 'newpeer' is registered_unratified ok
|
|
240
|
+
[4/6] PATCH .../peers/newpeer ok
|
|
235
241
|
[5/6] verify peer_ratifications audit row ok (id=N reason='...')
|
|
236
242
|
[6/6] invalidate local TTL cache ok
|
|
237
243
|
```
|
|
@@ -279,7 +285,7 @@ Hi! How can I help...
|
|
|
279
285
|
|
|
280
286
|
### `swarph import`
|
|
281
287
|
|
|
282
|
-
|
|
288
|
+
Session import is the **knowledge half of onboarding** — gives a memory-carrying peer (or a human migrating between CLIs) the substantive context they're bringing into the swarph, paired with the contract half (the handshake DM acknowledging the four invariants).
|
|
283
289
|
|
|
284
290
|
```bash
|
|
285
291
|
# Inspect what would be imported (lossy → honest framing)
|
|
@@ -305,7 +311,7 @@ To proceed:
|
|
|
305
311
|
|
|
306
312
|
**What's dropped:** attachments (would need re-upload), provider-side KV cache, conversation IDs, `cache_control` annotations.
|
|
307
313
|
|
|
308
|
-
Honest framing
|
|
314
|
+
Honest framing: **teleport is "import + continue", not "freeze and resume"** — the first turn after import on a new provider pays cold-cache cost.
|
|
309
315
|
|
|
310
316
|
```bash
|
|
311
317
|
$ swarph "say pong" --provider gemini
|
|
@@ -380,32 +386,14 @@ Design spec: `docs/superpowers/specs/2026-06-11-swarph-context-compressor-design
|
|
|
380
386
|
```
|
|
381
387
|
- Pretty-printed parsed dict on stdout when parse succeeds; `error_class=malformed_json` shows up in the stderr attribution footer when it doesn't.
|
|
382
388
|
|
|
383
|
-
## Spec
|
|
384
|
-
|
|
385
|
-
→ [hedge-fund-mcp / research/swarph_cli/PLAN.md](https://github.com/darw007d/hedge-fund-mcp/blob/main/research/swarph_cli/PLAN.md)
|
|
386
|
-
|
|
387
|
-
## Phase rollout
|
|
388
|
-
|
|
389
|
-
| Phase | What lands |
|
|
390
|
-
|---|---|
|
|
391
|
-
| **0** | Scaffold — entry-point + status banner |
|
|
392
|
-
| **2** (v0.1.0) | One-shot mode: `swarph "hello" --provider gemini` |
|
|
393
|
-
| **2.5** (v0.2.0) | `swarph import` — Claude JSONL → swarph-native session format |
|
|
394
|
-
| **5** (v0.3.0) | `swarph chat` interactive REPL — multi-turn against any of five adapters + slash commands |
|
|
395
|
-
| **5.5** (v0.4.0) | `swarph onboard` + `swarph ratify` — six mechanics steps + handshake template + witness flip (PLAN.md §15) |
|
|
396
|
-
| **5.6** (v0.5.0 — this release) | **`swarph daemon`** — foreground inbox drain loop with atomic cursor writes; retires the orphaned-tail-F class (PLAN.md §16) |
|
|
397
|
-
| **5.6b** | REPL drain coroutine + `/inbox`/`/reply` slash commands + `@swarph.on_dm()` handler registration (mesh + cli) |
|
|
398
|
-
| **3** | `--ask <peer>` mesh-aware one-shot via MeshClient |
|
|
399
|
-
| **6** | (already done) PyPI publish |
|
|
400
|
-
|
|
401
389
|
## Why split CLI from substrate
|
|
402
390
|
|
|
403
|
-
`swarph-mesh`
|
|
391
|
+
The [`swarph-mesh`](https://github.com/BrainSurfing-tech/swarph-mesh) library is imported by any program that wants to drive the mesh against the Protocol directly — orchestrators, judges, automation. Those callers don't need the CLI surface or the console-script entry point. Keeping the CLI in a separate repo means library users `pip install swarph-mesh` without pulling argparse + REPL plumbing they'll never run, while `pip install swarph-cli` gives you the standalone `swarph` binary.
|
|
404
392
|
|
|
405
393
|
## Install (dev)
|
|
406
394
|
|
|
407
395
|
```bash
|
|
408
|
-
git clone https://github.com/
|
|
396
|
+
git clone https://github.com/BrainSurfing-tech/swarph-cli
|
|
409
397
|
cd swarph-cli
|
|
410
398
|
python -m venv venv && source venv/bin/activate
|
|
411
399
|
pip install -e ".[dev]"
|