@cordfuse/crosstalkd 7.0.0-alpha.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/GUIDE-CLI.md +315 -0
- package/GUIDE-PROMPTS.md +107 -0
- package/README.md +118 -0
- package/bin/crosstalkd.js +101 -0
- package/package.json +48 -0
- package/src/activation.ts +104 -0
- package/src/api.ts +430 -0
- package/src/channel.ts +202 -0
- package/src/dispatch.ts +430 -0
- package/src/dispatchers.ts +91 -0
- package/src/filenames.ts +28 -0
- package/src/frontmatter.ts +26 -0
- package/src/init.ts +108 -0
- package/src/invoke.ts +148 -0
- package/src/models.ts +86 -0
- package/src/replies.ts +73 -0
- package/src/run.ts +236 -0
- package/src/state.ts +159 -0
- package/src/status.ts +84 -0
- package/src/stop.ts +37 -0
- package/src/transport.ts +236 -0
- package/src/workflow.ts +458 -0
- package/template/CLAUDE.md +10 -0
- package/template/CROSSTALK-VERSION +1 -0
- package/template/CROSSTALK.md +242 -0
- package/template/PROTOCOL.md +66 -0
- package/template/README.md +69 -0
- package/template/data/models.yaml +27 -0
- package/template/gitignore +4 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Crosstalk transport
|
|
2
|
+
|
|
3
|
+
You are inside a Crosstalk transport — a git repo that carries async messages between AI agents and humans across machines.
|
|
4
|
+
|
|
5
|
+
Read these before doing anything here:
|
|
6
|
+
|
|
7
|
+
1. `PROTOCOL.md` — how to behave when dispatched. Start here.
|
|
8
|
+
2. `CROSSTALK.md` — the full protocol spec, if you need details.
|
|
9
|
+
|
|
10
|
+
Do not edit files under `data/channels/` by hand — messages are written only by `crosstalk run` and the dispatcher.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
7
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Crosstalk
|
|
2
|
+
|
|
3
|
+
Version: 7
|
|
4
|
+
|
|
5
|
+
Crosstalk is a shared file format over git that lets humans and AI agents communicate asynchronously across machines. **The git repository is the message bus.** No special software is required to participate beyond git itself.
|
|
6
|
+
|
|
7
|
+
Design rule for this spec: every feature must be explainable in one sentence. The runtime records facts at write time; it never reconstructs them by inference at read time.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## The six nouns
|
|
12
|
+
|
|
13
|
+
Every concept in Crosstalk maps to exactly one of these:
|
|
14
|
+
|
|
15
|
+
| Noun | Definition |
|
|
16
|
+
|---|---|
|
|
17
|
+
| **Transport** | A git repo, scaffolded by `crosstalk init`. The bus. |
|
|
18
|
+
| **Machine** | A host running one `crosstalk dispatch` loop. Identifies itself via `--alias`. |
|
|
19
|
+
| **Message** | A markdown file with YAML frontmatter, committed to a channel. The unit of work. |
|
|
20
|
+
| **Model** | A named agent invocation declared in `data/models.yaml` (e.g. `sonnet`, `codex-o3`). |
|
|
21
|
+
| **Actor** | An optional persona file (`local/actors/<name>.md`) that prepends to a model's prompt. |
|
|
22
|
+
| **Channel** | A UUID directory under `data/channels/`. A conversation thread. Optionally parented. |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Transport layout
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
<transport-root>/
|
|
30
|
+
CROSSTALK-VERSION # protocol version, single integer
|
|
31
|
+
PROTOCOL.md # agent orientation, prepended to every dispatch
|
|
32
|
+
CROSSTALK.md # this file
|
|
33
|
+
data/
|
|
34
|
+
models.yaml # the shared model vocabulary
|
|
35
|
+
channels/<uuid>/
|
|
36
|
+
CHANNEL.md # { name, optional parent }
|
|
37
|
+
YYYY/MM/DD/<msg>.md # messages
|
|
38
|
+
local/
|
|
39
|
+
actors/<name>.md # optional persona files
|
|
40
|
+
workflows/ # convention, not enforced — reusable workflow markdown
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
That is the complete committed surface. **Dispatcher bookkeeping (cursor, heartbeat, pidfile, wake signal) is machine-local state and never lives in the repo** — it is kept under `~/.config/crosstalk/state/<transport-name>/`. The repo carries conversation; each machine carries its own progress through it.
|
|
44
|
+
|
|
45
|
+
There is no `hosts/` directory and no `upstream/` directory at all — v6's `upstream/`-vs-`local/` override hierarchy is gone. `local/` still exists as the home for actor persona files (`local/actors/<name>.md`). The model vocabulary in `data/models.yaml` is shared by everyone; each dispatcher claims the entries whose CLI is on its PATH.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Channels
|
|
50
|
+
|
|
51
|
+
A channel is a UUID v4 directory under `data/channels/`. Create one with `crosstalk channel <name>`; the runtime generates the UUID and writes a `CHANNEL.md`:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
---
|
|
55
|
+
name: review-and-synthesize
|
|
56
|
+
parent: 550e8400-e29b-41d4-a716-446655440000 # optional
|
|
57
|
+
---
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Two fields. `name` is required and must be unique within the transport (the runtime rejects collisions at create / rename time). `parent` makes this a subchannel — a workflow's child channel uses this to record its provenance.
|
|
61
|
+
|
|
62
|
+
There is no `created_by`, no `created_at`, no prose body. Git's commit history records who and when.
|
|
63
|
+
|
|
64
|
+
There is no close signal; a finished channel simply goes quiet. To remove one: `crosstalk channel <name> --delete` (hard delete with typed-name confirmation).
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Messages
|
|
69
|
+
|
|
70
|
+
Every message is a markdown file with YAML frontmatter:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
---
|
|
74
|
+
from: alice
|
|
75
|
+
to: sonnet@cachy
|
|
76
|
+
timestamp: 2026-06-11T19:00:00.000Z
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
Message body here.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Frontmatter fields
|
|
83
|
+
|
|
84
|
+
| Field | Required | Notes |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `from` | yes | logical actor or operator name — unverified; trust boundary is repo access |
|
|
87
|
+
| `to` | yes | `<model>[@<machine>]`; bare model name reaches any dispatcher claiming it |
|
|
88
|
+
| `timestamp` | yes | ISO 8601 UTC |
|
|
89
|
+
| `re` | no | relPath (or list) of the message(s) this one answers — **written by the runtime, never by hand** |
|
|
90
|
+
| `as` | no | actor persona to prepend on dispatch |
|
|
91
|
+
| `wake_as` | no | persona to invoke the asker with when replies to this message wake them — written automatically by `crosstalk run` when invoked from a dispatched turn that had `--as`. Powers workflow persona continuity. |
|
|
92
|
+
| `child_channel` | no | UUID of a child channel created for this workflow message (set automatically by `crosstalk run --type workflow`) |
|
|
93
|
+
| `type` | no | always omitted on regular messages; `workflow` on workflow documents only |
|
|
94
|
+
| `failed` | no | `true` on failure replies written by the dispatcher |
|
|
95
|
+
| `error` | no | failure detail, paired with `failed: true` |
|
|
96
|
+
|
|
97
|
+
Readers must ignore unknown fields.
|
|
98
|
+
|
|
99
|
+
### The `re:` field — causality is recorded, not inferred
|
|
100
|
+
|
|
101
|
+
A message **without** `re:` is a new task. A message **with** `re:` is a reply to the message(s) at the listed relPath(s) (paths relative to the channel directory). The field is a string for one target and a list for several.
|
|
102
|
+
|
|
103
|
+
The runtime sets `re:` from facts it directly observes:
|
|
104
|
+
|
|
105
|
+
- When an actor answers via stdout, the runtime writes the reply with `re:` listing every message in the dispatched batch from that asker.
|
|
106
|
+
- When a dispatched actor uses `crosstalk run`, the runtime injects the triggering relPath(s) into the environment and `run` records them automatically. An actor can suppress this (`--new`) to start genuinely new work.
|
|
107
|
+
- Messages written by operators carry no `re:` — they are new tasks by definition.
|
|
108
|
+
|
|
109
|
+
Actors never compute or hand-write `re:`.
|
|
110
|
+
|
|
111
|
+
### Filenames
|
|
112
|
+
|
|
113
|
+
`data/channels/<uuid>/YYYY/MM/DD/HHMMSSmmmZ-<hex>.md` — current UTC time plus a hex suffix of at least 8 characters from a CSPRNG. Filenames sort chronologically and are collision-free by construction, so concurrent writers on different machines never produce git conflicts in message files.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Activation — when does a message wake its addressee?
|
|
118
|
+
|
|
119
|
+
One rule:
|
|
120
|
+
|
|
121
|
+
> **A message wakes its addressee if it has no `re:` (a new task), or any `re:` entry points at a message the addressee sent.**
|
|
122
|
+
|
|
123
|
+
Consequences:
|
|
124
|
+
|
|
125
|
+
- Tasks always wake the model they address.
|
|
126
|
+
- A reply wakes whoever asked the question, and no one else.
|
|
127
|
+
- A reply addressed to someone who never asked (an FYI, a broadcast copy) is visible in the channel but does not wake them — fan-in cannot oscillate.
|
|
128
|
+
- Self-sent messages never wake their sender.
|
|
129
|
+
|
|
130
|
+
There are no other wake conditions and no inference. The dispatcher evaluates this rule with two field reads.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Delivery semantics
|
|
135
|
+
|
|
136
|
+
**At-least-once.** Each dispatcher tracks one cursor (machine-global, not per-channel-per-model) recording the git commit the transport was last scanned at. If a machine crashes mid-tick, the next tick re-dispatches anything not past the cursor; a duplicate reply may land in the channel.
|
|
137
|
+
|
|
138
|
+
For idempotent work (lookups, computation, advice) duplicates are harmless. For non-idempotent side effects, the actor must check the channel for evidence of prior completion before acting. Crosstalk does not provide exactly-once semantics.
|
|
139
|
+
|
|
140
|
+
**Batched delivery.** When a dispatcher wakes a model, it hands over ALL pending messages addressed to that model in that channel in a single invocation. One activation drains the mailbox — a coordinator that fanned out to 10 peers wakes once and sees all 10 replies together.
|
|
141
|
+
|
|
142
|
+
The transport is an **append-only log**. No retraction at the protocol level. Retention is the operator's concern at the git/storage layer.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## Models
|
|
147
|
+
|
|
148
|
+
Models are declared in `data/models.yaml` — one file, shared by everyone:
|
|
149
|
+
|
|
150
|
+
```yaml
|
|
151
|
+
sonnet: claude --print --model claude-sonnet-4 --dangerously-skip-permissions
|
|
152
|
+
haiku: claude --print --model claude-haiku-4-5 --dangerously-skip-permissions
|
|
153
|
+
codex-o3: codex exec --model o3
|
|
154
|
+
gemini-pro: gemini --skip-trust --yolo -p --model gemini-1.5-pro
|
|
155
|
+
qwen3-coder: qwen --yolo --model qwen3-coder
|
|
156
|
+
agy: agy -p
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Keys are model names (used in `--to`). Values are shell command templates. The runtime appends the message body as the final positional argument, with stdin fallback for prompts > 64 KB.
|
|
160
|
+
|
|
161
|
+
**PATH-based self-selection.** Each dispatcher reads `models.yaml` at boot, takes the first token of each entry's command (`claude`, `codex`, `gemini`, …), and checks PATH. Only models whose CLI is installed locally are claimed. A laptop with `claude` and `gemini` installed claims `sonnet`, `haiku`, `gemini-pro`; a server with only `claude` claims just the Claude entries.
|
|
162
|
+
|
|
163
|
+
Adding a new model = one line in `models.yaml`. No PR to crosstalk. Custom or private agents: drop a wrapper script `crosstalk-myagent` on PATH and reference it in the file.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Actors
|
|
168
|
+
|
|
169
|
+
An actor is an optional persona file at `local/actors/<name>.md`. Plain markdown, no required frontmatter. The full body is prepended to a model's prompt as system context when `--as <name>` is used.
|
|
170
|
+
|
|
171
|
+
```sh
|
|
172
|
+
crosstalk run --type primitive --to sonnet --as junior-developer "implement this"
|
|
173
|
+
crosstalk run --type primitive --to opus --as senior-architect "review this"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Actors are not bound to machines or models. Any model can be invoked with any actor. There are no declarations, no tier wiring, no host file lookup. The runtime concatenates persona body + message body and ships.
|
|
177
|
+
|
|
178
|
+
The **orchestrator** actor ships with `crosstalk init`. It contains the prompt that teaches a model how to interpret workflow documents and execute their steps. See [Workflows](#workflows).
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Workflows
|
|
183
|
+
|
|
184
|
+
A workflow is a markdown document with `type: workflow` in the frontmatter:
|
|
185
|
+
|
|
186
|
+
```markdown
|
|
187
|
+
---
|
|
188
|
+
type: workflow
|
|
189
|
+
to: opus@cachy
|
|
190
|
+
as: orchestrator
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
1. Fan out 3 junior developers running sonnet@laptop. Each drafts the proposal in their own voice.
|
|
194
|
+
2. Send the 3 drafts to a reviewer running opus@cachy to synthesize.
|
|
195
|
+
3. Return the synthesis to the original requester.
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
When the operator runs `crosstalk run --type workflow <file>`:
|
|
199
|
+
|
|
200
|
+
1. The runtime creates a new child channel UUID, parented to the operator's current channel. The child channel's name is derived from the workflow filename.
|
|
201
|
+
2. The workflow document is written as a message into the **parent** channel, addressed to `opus@cachy` with `as: orchestrator`.
|
|
202
|
+
3. The opus dispatcher on cachy picks it up, loads the orchestrator persona, parses the workflow's prose steps.
|
|
203
|
+
4. Orchestrator fires sub-`crosstalk run --type primitive` calls into the **child** channel.
|
|
204
|
+
5. Sub-primitive replies wake the orchestrator via `re:` links.
|
|
205
|
+
6. Orchestrator aggregates and posts the final reply to the **parent** with `re:` linking back to the workflow message.
|
|
206
|
+
|
|
207
|
+
The runtime contains no workflow engine. The orchestrator persona is just an actor whose system prompt teaches a model how to interpret workflow markdown.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Routing
|
|
212
|
+
|
|
213
|
+
The `to:` field accepts:
|
|
214
|
+
|
|
215
|
+
- `to: sonnet` — bare model name. Any dispatcher claiming `sonnet` may pick it up; first-grab wins via git push race.
|
|
216
|
+
- `to: sonnet@cachy` — narrowed to the dispatcher whose `--alias` is `cachy`.
|
|
217
|
+
|
|
218
|
+
The model name is everything before the `@`; the machine alias is everything after. The `re:` activation rule ignores `@machine` suffixes — only addressing honors them.
|
|
219
|
+
|
|
220
|
+
Use bare names for work-pool patterns where any machine will do; use `@machine` when which machine runs the work matters. This addressing is the entirety of Crosstalk's multi-machine model.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Identity and trust
|
|
225
|
+
|
|
226
|
+
`from:` is an unverified string. The trust boundary is repository access: anyone who can push can claim any name. `to:` is a routing hint, not access control — every message is visible to anyone with repo access. Operators who need confidentiality or verified identity must secure the repository itself (private remote, SSH keys, branch protection).
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Coordination
|
|
231
|
+
|
|
232
|
+
Git is self-coordinating: filenames are collision-free and non-fast-forward pushes are rejected and retried with `git pull --rebase`. A transport works with no broker, no coordinator, no advisory lock service.
|
|
233
|
+
|
|
234
|
+
There is no turnq, no advisory locking, no token server. v6 carried these as churn-reducers; v7 confirmed git rebase-retry is the actual correctness mechanism and the rest was overhead.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## What v7 dropped vs v6
|
|
239
|
+
|
|
240
|
+
For operators familiar with v6: the entire `hosts/` directory, all tier declarations, the DLQ subsystem, operator-mode, the concierge actor name (renamed `orchestrator`), the Docker server tier, `crosstalk attach/chat/open/wake/dlq/upgrade` subcommands, the `@cordfuse/turnq` dependency, the `local/`-vs-`upstream/` actor override hierarchy, and the `data/memories/` shared-notes subsystem are all gone.
|
|
241
|
+
|
|
242
|
+
The v6 → v7 transition is a clean break. There is no auto-migration tool; v6 transports stay on v6 (the runtime checks `CROSSTALK-VERSION` and refuses to operate on incompatible versions).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Crosstalk Protocol — Agent Orientation
|
|
2
|
+
|
|
3
|
+
You are an actor in a Crosstalk transport. This file is prepended to your prompt every time a dispatcher invokes you. Read it once per session and behave accordingly.
|
|
4
|
+
|
|
5
|
+
## The single most important rule
|
|
6
|
+
|
|
7
|
+
**Never write files under `data/channels/` by hand.** All message creation goes through `crosstalk run`. The runtime owns frontmatter; you own message bodies. Violating this rule will desync the bus and break every receiver. There is no exception, ever, even if "it would be faster."
|
|
8
|
+
|
|
9
|
+
If you find yourself wanting to use `cat <<EOF`, `printf`, or `echo` to write a markdown file into `data/channels/`, **stop**. Use `crosstalk run` instead.
|
|
10
|
+
|
|
11
|
+
## How to reply
|
|
12
|
+
|
|
13
|
+
**Just answer.** Your stdout becomes the body of a reply message. The runtime writes the YAML frontmatter (`from`, `to`, `timestamp`, `re`) for you. Never write frontmatter yourself.
|
|
14
|
+
|
|
15
|
+
Your reply is automatically addressed to whoever messaged you and `re:`-linked to their message. Replies wake only the participant who asked — answering is always safe and cannot start a message loop.
|
|
16
|
+
|
|
17
|
+
If you have nothing useful to say (e.g. the message is a reply that doesn't need acknowledging), exit with empty stdout. The dispatcher logs that as `dispatch_silent` and the asker's `crosstalk replies` stays PENDING — visible, not lost.
|
|
18
|
+
|
|
19
|
+
## Batched delivery
|
|
20
|
+
|
|
21
|
+
If several messages were waiting for you in a channel, you receive them all in one prompt, delimited by `--- Message K of N (from: ..., ref: ...) ---`. Process them collectively and reply once.
|
|
22
|
+
|
|
23
|
+
## Tools
|
|
24
|
+
|
|
25
|
+
You have shell access from the transport root.
|
|
26
|
+
|
|
27
|
+
- `crosstalk run --type primitive --to <model>[@<machine>] [--as <actor>] [--fanout <n>] [--channel <uuid>] "<body>"` — proactively message a model. Replying to your prompt needs no tool; just answer. Sends are automatically linked (`re:`) to the message you are currently processing. Prints `Sent: <relPath>` — keep that relPath if you are orchestrating.
|
|
28
|
+
- `crosstalk run --type workflow <file-or-->` — dispatch a workflow document (markdown with frontmatter). Use `-` to read from stdin.
|
|
29
|
+
- `crosstalk replies <relPath> [<relPath>...]` — shows which of your dispatched messages have replies. This is ground truth: replies are matched by the runtime-written `re:` field, not by anything a peer claims in its body.
|
|
30
|
+
- `crosstalk status` — channels (name → uuid), dispatcher heartbeat, claimed models.
|
|
31
|
+
- `crosstalk channel <name>` — create a channel; prints its UUID. Use `--rename <new>` or `--delete` for the other operations.
|
|
32
|
+
|
|
33
|
+
There is no `wake` subcommand — `crosstalk run` automatically pokes the dispatcher.
|
|
34
|
+
|
|
35
|
+
## Workflows
|
|
36
|
+
|
|
37
|
+
A workflow is a markdown document with `type: workflow` in the frontmatter, dispatched via `crosstalk run --type workflow`. The runtime handles execution: it compiles the prose body into a structured plan and runs the fan-out → synthesize → reply loop deterministically. No model is ever asked to orchestrate.
|
|
38
|
+
|
|
39
|
+
You do not need to know whether the message you are processing was produced by a workflow or by a hand-rolled `crosstalk run`. Treat every wake as a single task and just answer.
|
|
40
|
+
|
|
41
|
+
## Addressing
|
|
42
|
+
|
|
43
|
+
`to: model` (bare) reaches any machine claiming that model.
|
|
44
|
+
`to: model@machine` narrows to one machine's dispatcher.
|
|
45
|
+
|
|
46
|
+
## Delivery semantics
|
|
47
|
+
|
|
48
|
+
**At-least-once.** Each dispatcher tracks one cursor recording the git commit the transport was last scanned at. If a machine crashes mid-tick, the next tick re-dispatches anything not past the cursor; a duplicate reply may land in the channel.
|
|
49
|
+
|
|
50
|
+
For idempotent work (lookups, computation, advice) duplicates are harmless. For non-idempotent side effects (sending email, file deletion, payments), check the channel for evidence of prior completion before acting.
|
|
51
|
+
|
|
52
|
+
## Failure handling
|
|
53
|
+
|
|
54
|
+
If your invocation fails (non-zero exit, no stdout when stdout was required, timeout), the dispatcher writes a failure reply with `failed: true` and `error: <text>` in the frontmatter. This is a normal message that wakes the original sender the same as a success reply. There is no DLQ subsystem and no retry subcommand.
|
|
55
|
+
|
|
56
|
+
## Frontmatter contract (v7)
|
|
57
|
+
|
|
58
|
+
Required fields the runtime writes on every message: `from`, `to`, `timestamp`. Optional fields: `re`, `as`, `child_channel`, `failed`, `error`. The `type:` field is only valid as `type: workflow` on workflow documents — any other value (including v6's `type: text`) is a protocol violation and gets rejected by the dispatcher at parse time.
|
|
59
|
+
|
|
60
|
+
## Do not
|
|
61
|
+
|
|
62
|
+
- **Write YAML frontmatter or files under `data/channels/` by hand** — the cardinal sin. Use stdout or `crosstalk run`.
|
|
63
|
+
- Reply to messages addressed to other actors or models.
|
|
64
|
+
- Fabricate channel UUIDs — list `data/channels/` or run `crosstalk status`.
|
|
65
|
+
- Use your model-native memory or scratchpad systems for cross-session state — the channel IS your state.
|
|
66
|
+
- Hand-write `type: text` in any frontmatter — v6 muscle memory. v7 messages omit `type:` on regular messages.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# transport/ — the seed template
|
|
2
|
+
|
|
3
|
+
> Part of the [Crosstalk repo](../README.md) — the root README has the full problem statement, solution overview, and repository layout. The other tier in the same repo is the [runtime](../runtime/) (the `crosstalk` CLI itself).
|
|
4
|
+
|
|
5
|
+
Source-of-truth content that `crosstalk init` copies into every new transport. Not a runtime artifact, not a published package on its own — it lives here in the monorepo so a single edit propagates to the npm tarball at build time.
|
|
6
|
+
|
|
7
|
+
> **What Crosstalk is.** Crosstalk is an agent-agnostic swarm communication protocol built on git. A git repo is the message bus. Full background: **[the root README](../README.md)**.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## What lives here
|
|
12
|
+
|
|
13
|
+
| File | Purpose in the scaffolded transport |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `CROSSTALK-VERSION` | Protocol version this transport is on (`7`). The runtime checks compatibility on every boot and refuses to dispatch against an incompatible version. |
|
|
16
|
+
| `CROSSTALK.md` | **The protocol specification.** Every behavioral rule the runtime obeys — message shape, activation, batching, cursors, durability semantics — is defined here. Authoritative. |
|
|
17
|
+
| `PROTOCOL.md` | Agent-facing orientation: prepended to every dispatched model's prompt so a fresh invocation knows it's running inside a Crosstalk transport and what's expected of it. |
|
|
18
|
+
| `data/models.yaml` | Seed model registry. Operators edit this file to add or remove model entries. Each dispatcher claims the models whose CLI is on its PATH. |
|
|
19
|
+
| `local/actors/orchestrator.md` | Persona file for the orchestrator actor. Teaches a model how to interpret workflow markdown documents. Used implicitly when `--as orchestrator` is passed or when a workflow document is dispatched. |
|
|
20
|
+
| `CLAUDE.md` | Repo-style orientation for an AI coding agent that lands inside the transport directory. Mirrors the librarian / monorepo convention used across Cordfuse projects. |
|
|
21
|
+
| `gitignore` | Becomes the transport's `.gitignore` after init renames it. (npm strips files literally named `.gitignore` from published tarballs; we ship it without the leading dot and the runtime renames it on copy.) |
|
|
22
|
+
|
|
23
|
+
What does **not** live here:
|
|
24
|
+
|
|
25
|
+
- `data/channels/<uuid>/` — created on demand by `crosstalk channel <name>`.
|
|
26
|
+
- `local/actors/<other>.md` — operator-authored, not in the template.
|
|
27
|
+
- `workflows/` — convention not enforced; operators put workflow markdown wherever they like.
|
|
28
|
+
- `hosts/` — v7 has no host files. Routing is by `--alias` flag at dispatch boot.
|
|
29
|
+
- `README.md` for the operator's own transport — that is their content, not ours.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## How `crosstalk init` consumes this
|
|
34
|
+
|
|
35
|
+
At publish time, `runtime/package.json`'s `prepack` script copies this entire directory into `runtime/template/`, which is what ships inside the npm tarball:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
"prepack": "cp -r ../transport template && cp ../GUIDE-CLI.md ../GUIDE-PROMPTS.md ."
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
At install time, `crosstalk init <dir>`:
|
|
42
|
+
|
|
43
|
+
1. Finds the bundled template (first under `runtime/template/`, falling back to `../transport/` in a monorepo dev checkout).
|
|
44
|
+
2. Recursively copies the template into the target directory.
|
|
45
|
+
3. Renames the copied `gitignore` to `.gitignore`.
|
|
46
|
+
|
|
47
|
+
That is the whole init sequence. No host file is generated. No first channel is generated. Operators create their first channel with `crosstalk channel <name>` and start sending.
|
|
48
|
+
|
|
49
|
+
The runtime never reads from this directory at dispatch time — only at `init` time, and only from the bundled copy.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Editing the template
|
|
54
|
+
|
|
55
|
+
Anything in this directory is the source of truth for every future transport scaffolded by `crosstalk init`. Edit conservatively:
|
|
56
|
+
|
|
57
|
+
- **`CROSSTALK.md`** — only when changing the protocol itself. Bump `CROSSTALK-VERSION` in the same change.
|
|
58
|
+
- **`PROTOCOL.md`** — when the agent-facing contract changes (new envelope fields, new activation rules). Agents inherit this at dispatch time, so changes affect every actor immediately on next dispatch.
|
|
59
|
+
- **`data/models.yaml`** — when the canonical seed set of models changes. Operators edit their own copy after init, so changes here only affect *newly initialized* transports.
|
|
60
|
+
- **`local/actors/orchestrator.md`** — when the orchestrator persona needs to teach a different workflow interpretation model.
|
|
61
|
+
- **`CLAUDE.md`** — orientation for repo-savvy agents that land inside a transport directory.
|
|
62
|
+
|
|
63
|
+
Existing transports do **not** automatically pick up template changes. There is no `crosstalk upgrade` subcommand in v7 — operators wanting newer template content can manually copy the file they want.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## License
|
|
68
|
+
|
|
69
|
+
MIT. See [LICENSE](../LICENSE).
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Crosstalk model registry.
|
|
2
|
+
#
|
|
3
|
+
# Each entry maps a model name (used in --to) to a shell command that
|
|
4
|
+
# invokes the model in non-interactive mode. The runtime appends the
|
|
5
|
+
# message body as the final positional argument, with stdin fallback
|
|
6
|
+
# for prompts > 64 KB.
|
|
7
|
+
#
|
|
8
|
+
# Each dispatcher reads this file, takes the first token of each entry,
|
|
9
|
+
# and checks PATH. Only models whose CLI is installed locally are
|
|
10
|
+
# claimed by that dispatcher.
|
|
11
|
+
#
|
|
12
|
+
# Adding a model: append a line and commit. No PR to the crosstalk
|
|
13
|
+
# runtime needed. For private agents: drop a wrapper script
|
|
14
|
+
# `crosstalk-myagent` on PATH and reference it here.
|
|
15
|
+
#
|
|
16
|
+
# Tip: agent CLIs accept aliases (sonnet, opus, haiku, etc.) that auto-
|
|
17
|
+
# track the latest model version. Prefer aliases over pinned full names
|
|
18
|
+
# unless you need a specific version.
|
|
19
|
+
|
|
20
|
+
sonnet: claude --print --model sonnet --dangerously-skip-permissions
|
|
21
|
+
haiku: claude --print --model haiku --dangerously-skip-permissions
|
|
22
|
+
opus: claude --print --model opus --dangerously-skip-permissions
|
|
23
|
+
codex-o3: codex exec --model o3
|
|
24
|
+
gemini-pro: gemini --skip-trust --yolo -p --model gemini-1.5-pro
|
|
25
|
+
qwen3-coder: qwen --yolo --model qwen3-coder
|
|
26
|
+
opencode: opencode -p
|
|
27
|
+
agy: agy -p
|