@interactive-inc/claude-funnel 0.24.0 → 0.25.1
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.
- package/README.md +41 -26
- package/dist/bin.js +372 -358
- package/dist/gateway/daemon.js +185 -185
- package/dist/index.d.ts +95 -26
- package/dist/index.js +174 -110
- package/funnel.schema.json +38 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,11 +36,11 @@ external sources outbound replies
|
|
|
36
36
|
|
|
37
37
|
Three concepts make up the model:
|
|
38
38
|
|
|
39
|
-
Channel — a named subscription box. Holds one or more connectors. An agent session subscribes to exactly one channel. Delivery is `fanout` (every subscriber sees every event, the default) or `exclusive` (one event per subscriber, round-robin — for worker pools).
|
|
39
|
+
Channel — a named subscription box (transport only). Holds one or more connectors and a delivery mode; it does not carry launch flags. An agent session subscribes to exactly one channel. Delivery is `fanout` (every subscriber sees every event, the default) or `exclusive` (one event per subscriber, round-robin — for worker pools).
|
|
40
40
|
|
|
41
41
|
Connector — a single attachment from a channel to an external source. Four types ship today: `slack`, `gh`, `discord`, `schedule`. The first three are bidirectional (events in, replies out); `schedule` is one-way (cron ticks in).
|
|
42
42
|
|
|
43
|
-
Profile — a saved launch preset
|
|
43
|
+
Profile — a saved launch preset. Bundles `{ path, channelId, options, env, resume }` so `fnl claude --profile cto` reproduces a known setup: which directory to launch from, which channel to bind, and the launch recipe (args prepended to the claude argv, env layered under the process, session reuse). The first profile in the list is the default.
|
|
44
44
|
|
|
45
45
|
The daemon is where all external connections live. It runs on port 9742, supervises connectors with auto-restart, broadcasts events to subscribed agent sessions over WebSocket, and serves the reply API that MCP calls. Starting or stopping an agent never starts or stops external connections.
|
|
46
46
|
|
|
@@ -84,11 +84,11 @@ fnl claude --channel ops
|
|
|
84
84
|
|
|
85
85
|
Every event the connector sees now arrives in the running agent session, and the agent can reply via the `my-slack` MCP tool.
|
|
86
86
|
|
|
87
|
-
Save it as a profile for one-command launches:
|
|
87
|
+
Save it as a profile for one-command launches — the profile carries the launch recipe:
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
|
-
fnl profiles add cto --path=/repo/myapp --channel=ops
|
|
91
|
-
fnl claude --profile cto # cd + channel binding in one shot
|
|
90
|
+
fnl profiles add cto --path=/repo/myapp --channel=ops --agent=pm --options="--brief"
|
|
91
|
+
fnl claude --profile cto # cd + channel binding + recipe in one shot
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
Or drop a `funnel.json` in the repo and `fnl claude` (no args) inside the repo will use it:
|
|
@@ -99,10 +99,6 @@ Or drop a `funnel.json` in the repo and `fnl claude` (no args) inside the repo w
|
|
|
99
99
|
"channels": [
|
|
100
100
|
{
|
|
101
101
|
"name": "ops",
|
|
102
|
-
"options": ["--brief", "--agent", "pm"],
|
|
103
|
-
"env": {
|
|
104
|
-
"ANTHROPIC_MODEL": "claude-sonnet-4-6"
|
|
105
|
-
},
|
|
106
102
|
"connectors": [
|
|
107
103
|
{
|
|
108
104
|
"type": "slack",
|
|
@@ -115,7 +111,19 @@ Or drop a `funnel.json` in the repo and `fnl claude` (no args) inside the repo w
|
|
|
115
111
|
]
|
|
116
112
|
},
|
|
117
113
|
{
|
|
118
|
-
"name": "review"
|
|
114
|
+
"name": "review"
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"profiles": [
|
|
118
|
+
{
|
|
119
|
+
"name": "ops-pm",
|
|
120
|
+
"channel": "ops",
|
|
121
|
+
"options": ["--brief", "--agent", "pm"],
|
|
122
|
+
"env": { "ANTHROPIC_MODEL": "claude-sonnet-4-6" }
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"name": "review-reviewer",
|
|
126
|
+
"channel": "review",
|
|
119
127
|
"options": ["--agent", "reviewer"]
|
|
120
128
|
}
|
|
121
129
|
]
|
|
@@ -124,11 +132,11 @@ Or drop a `funnel.json` in the repo and `fnl claude` (no args) inside the repo w
|
|
|
124
132
|
|
|
125
133
|
`channels[]` is required and the first entry is the default. `fnl claude --channel review` picks one by name; `fnl claude` with no `--channel` uses the first.
|
|
126
134
|
|
|
127
|
-
|
|
135
|
+
A channel declares only transport — its `connectors` and delivery mode. The launch recipe lives on `profiles[]`: each profile binds to a channel by name and carries `options` (prepended to the claude argv before user-supplied CLI args, which still come last — use it for flags like `--brief`, `--agent <name>`, `--model <name>`), `env` (layered under the launched claude process — `process.env` from the launching shell wins on collision), and `resume`. `fnl claude` applies the first profile bound to the chosen channel.
|
|
128
136
|
|
|
129
137
|
The optional `connectors` array on a channel is the source of truth for that channel: missing connectors are created, an existing connector matched by token under a different name is renamed in place, and connectors not declared are removed on launch. An absent `connectors` field leaves `~/.funnel` alone.
|
|
130
138
|
|
|
131
|
-
On launch, the chosen channel's
|
|
139
|
+
On launch, the chosen channel's transport (`connectors`, delivery) is materialized into the global `~/.funnel/settings.json` Channel entry; the profile recipe is passed straight to the launcher and is not persisted there. Raw launches (`fnl claude --channel <name>` without funnel.json) bind transport only and carry no recipe.
|
|
132
140
|
|
|
133
141
|
The optional top-level `$schema` points at the JSON Schema so editors can validate and autocomplete the file. The recommended reference for repos with a local install is `./node_modules/@interactive-inc/claude-funnel/funnel.schema.json` — it works without a network round-trip and editors do not need to prompt for trust. The same file is also published at `https://interactive-inc.github.io/open-claude-funnel/funnel.schema.json` (editors usually require explicit trust on first use), and `fnl schema > funnel.schema.json` regenerates a local copy on demand.
|
|
134
142
|
|
|
@@ -188,10 +196,12 @@ fnl channels <ch> connectors <c> schedules add <id> --cron="<expr>" --prompt="<t
|
|
|
188
196
|
fnl channels <ch> connectors <c> schedules remove <id>
|
|
189
197
|
|
|
190
198
|
fnl profiles list (first entry is the default)
|
|
191
|
-
fnl profiles add <name> --path=<dir> --channel=<channel-name>
|
|
199
|
+
fnl profiles add <name> --path=<dir> --channel=<channel-name> \
|
|
200
|
+
[--agent=<name>] [--options="<argv>"] [--env="K=V,K2=V2"] [--no-resume]
|
|
192
201
|
fnl profiles <name> launch (alias for `<name> run`)
|
|
193
202
|
fnl profiles <name> run launch (sugar for `fnl claude --profile <name>`)
|
|
194
|
-
fnl profiles <name> set [--path=...] [--channel=...]
|
|
203
|
+
fnl profiles <name> set [--path=...] [--channel=...] \
|
|
204
|
+
[--agent=...] [--options="..."] [--env="..."] [--resume|--no-resume]
|
|
195
205
|
fnl profiles <name> as-default move to the front of the list
|
|
196
206
|
fnl profiles rename <old> <new>
|
|
197
207
|
fnl profiles remove <name>
|
|
@@ -245,10 +255,9 @@ To invoke a connector from outside an agent, the same path is reachable as `fnl
|
|
|
245
255
|
## Data model
|
|
246
256
|
|
|
247
257
|
```
|
|
248
|
-
Channel = { id, name, delivery,
|
|
249
|
-
subscription box
|
|
250
|
-
or `exclusive` (round-robin one client per event).
|
|
251
|
-
launch; env layers under the launched process (process.env wins on collision)
|
|
258
|
+
Channel = { id, name, delivery, connectors[] }
|
|
259
|
+
subscription box (transport only). delivery is `fanout` (every WS client sees every event)
|
|
260
|
+
or `exclusive` (round-robin one client per event). carries no launch settings.
|
|
252
261
|
|
|
253
262
|
Connector =
|
|
254
263
|
| { type: "slack", name, botToken, appToken } Slack Socket Mode
|
|
@@ -256,17 +265,23 @@ Connector =
|
|
|
256
265
|
| { type: "discord", name, botToken } Discord Gateway
|
|
257
266
|
| { type: "schedule", name, entries[] } cron-driven; entries = { id, cron, prompt, enabled?, catchupPolicy? }
|
|
258
267
|
|
|
259
|
-
Profile = { name, path, channelId }
|
|
260
|
-
named launch preset
|
|
268
|
+
Profile = { name, path, channelId, options[], env, resume }
|
|
269
|
+
named launch preset: where to launch (path), which channel to bind, and the launch recipe —
|
|
270
|
+
options[] prepends to the claude argv, env layers under the process (process.env wins on
|
|
271
|
+
collision), resume toggles session reuse. the first profile is the default.
|
|
261
272
|
|
|
262
|
-
LocalConfig = { channels: ChannelSpec[] }
|
|
273
|
+
LocalConfig = { channels: ChannelSpec[], profiles?: ProfileSpec[] }
|
|
263
274
|
per-repo file (funnel.json). channels[] required; first entry is default, --channel selects.
|
|
264
275
|
|
|
265
|
-
ChannelSpec = { name,
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
276
|
+
ChannelSpec = { name, connectors? }
|
|
277
|
+
transport declaration (no id, since funnel.json declares by name). connectors materialize into
|
|
278
|
+
the matching Channel in ~/.funnel/settings.json on launch. Connector token fields accept a
|
|
279
|
+
literal, an env-var reference at `env.<field>` resolved from process.env and ./.env.local, or
|
|
280
|
+
omission for a TTY prompt persisted to ~/.funnel.
|
|
281
|
+
|
|
282
|
+
ProfileSpec = { name, channel, options?, env?, resume? }
|
|
283
|
+
launch recipe bound to a channel by name. applied inline on launch (the first spec bound to the
|
|
284
|
+
chosen channel); not persisted into the global profiles[] list.
|
|
270
285
|
|
|
271
286
|
Settings = { channels[], profiles[] } → ~/.funnel/settings.json
|
|
272
287
|
```
|