@north-light/crouter 0.3.332 → 0.3.333
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 +2 -2
- package/dist/api/command-manifest/manifest.js +1 -1
- package/dist/build-root.js +1 -1
- package/dist/builtin-memory/crouter-concepts/INDEX.md +13 -0
- package/dist/builtin-memory/crouter-concepts/README.md +19 -0
- package/dist/builtin-memory/crouter-concepts/lifecycle-and-wakes.md +28 -0
- package/dist/builtin-memory/crouter-concepts/memory.md +36 -0
- package/dist/builtin-memory/crouter-concepts/nodes-and-the-canvas.md +30 -0
- package/dist/builtin-memory/crouter-concepts/profiles-kinds-and-modes.md +33 -0
- package/dist/builtin-memory/crouter-concepts/scopes-and-trust.md +34 -0
- package/dist/builtin-memory/crouter-concepts/why-a-daemon.md +31 -0
- package/dist/builtin-memory/crouter-plugin/README.md +7 -7
- package/dist/builtin-memory/crouter-plugin/commands.md +1 -1
- package/dist/builtin-memory/crouter-plugin/deploying.md +1 -1
- package/dist/builtin-memory/crouter-plugin/getting-started.md +1 -1
- package/dist/clients/attach/input/capabilities.js +1 -1
- package/dist/clients/attach/overlays/help.js +1 -1
- package/dist/clients/attach/slash/dispatch.js +1 -1
- package/dist/clients/attach/viewer.js +413 -413
- package/dist/commands/sys/branch.js +1 -1
- package/dist/commands/sys/setup-core.d.ts +1 -1
- package/dist/commands/sys/setup-core.js +4 -4
- package/dist/commands/sys/tutorial/branch.d.ts +1 -0
- package/dist/commands/sys/tutorial/branch.js +1 -0
- package/dist/commands/sys/tutorial/lessons.d.ts +6 -0
- package/dist/commands/sys/tutorial/lessons.js +12 -0
- package/dist/commands/sys/tutorial/scenario.d.ts +1 -0
- package/dist/commands/sys/tutorial/scenario.js +2 -0
- package/dist/commands/sys/tutorial/tracks.d.ts +2 -0
- package/dist/commands/sys/tutorial/tracks.js +4 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/runtime/boot-root.d.ts +7 -0
- package/dist/core/runtime/boot-root.js +4 -4
- package/dist/core/runtime/first-run-offer.d.ts +11 -0
- package/dist/core/runtime/first-run-offer.js +5 -0
- package/dist/core/runtime/front-door.js +3 -3
- package/dist/types.js +1 -1
- package/docs/cli/README.md +16 -0
- package/docs/cli/canvas-and-dashboard.md +56 -0
- package/docs/cli/first-session.md +55 -0
- package/docs/cli/human-inbox.md +34 -0
- package/docs/cli/memory-and-preferences.md +50 -0
- package/docs/cli/the-viewer.md +79 -0
- package/docs/concepts/README.md +17 -0
- package/docs/concepts/lifecycle-and-wakes.md +26 -0
- package/docs/concepts/memory.md +34 -0
- package/docs/concepts/nodes-and-the-canvas.md +28 -0
- package/docs/concepts/profiles-kinds-and-modes.md +31 -0
- package/docs/concepts/scopes-and-trust.md +32 -0
- package/docs/concepts/why-a-daemon.md +29 -0
- package/package.json +8 -8
- package/runtime.lock.json +196 -196
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Memory and preferences
|
|
3
|
+
description: When you want later agents to retain a fact or follow an instruction, read this page because it explains where memory is stored and how to inspect or revise it.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory and preferences
|
|
7
|
+
|
|
8
|
+
You can give future agents useful context without pasting the same background into every conversation. Ask an agent to remember a durable fact or instruction, then inspect the saved memory yourself from the terminal.
|
|
9
|
+
|
|
10
|
+
## Tell an agent what should persist
|
|
11
|
+
|
|
12
|
+
Say what should be remembered and where it applies.
|
|
13
|
+
|
|
14
|
+
| If you want to save | Tell the agent |
|
|
15
|
+
|---|---|
|
|
16
|
+
| A fact or procedure | “Remember that our staging database is reset every Friday.” |
|
|
17
|
+
| An instruction about how to work | “Remember that I want a short recommendation before any production change.” |
|
|
18
|
+
| Something for every project you use | “Remember this as a user preference.” |
|
|
19
|
+
| Something only agents in this repository need | “Remember this for this project.” |
|
|
20
|
+
|
|
21
|
+
A preference tells an agent how to act. Knowledge gives it facts or a procedure to consult. The narrowest useful store is best: a user memory follows you everywhere, while a project memory belongs to one repository. For the explanation of memory tiers and loading, see [Memory](../concepts/memory.md).
|
|
22
|
+
|
|
23
|
+
## Browse what was saved
|
|
24
|
+
|
|
25
|
+
List the memory documents available in your current context:
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
crtr memory list
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Read one by its name from that list:
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
crtr memory read <name>
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`crtr memory read` resolves the current winning document when the same name exists at more than one scope. Add `--scope user` to read only user memory, or `--dir <project-directory>` to inspect one exact project store.
|
|
38
|
+
|
|
39
|
+
## Edit a memory document
|
|
40
|
+
|
|
41
|
+
Memory revisions are intentional and recorded. To replace a document's body, pipe the complete replacement text to `crtr memory edit` and give the reason for the revision:
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
printf '%s\n' 'Production changes need an explicit approval.' | \
|
|
45
|
+
crtr memory edit <name> --rationale "Updated the approval rule."
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`crtr memory edit` replaces the whole body you pipe; it does not append text. Use `crtr memory history <name>` to read the revision history. If you want to create a document yourself, use `crtr memory write`; it requires a kind, a routing sentence that tells agents when to read it, and the document body.
|
|
49
|
+
|
|
50
|
+
Memory is for reusable current truth and durable instructions, not a transcript of one conversation. When a fact changes, update the existing document rather than saving a second version.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: The viewer
|
|
3
|
+
description: When you are watching or driving a node in tmux, read this page because it lists the viewer controls, slash commands, and the difference between a prompt, a steer, and an interrupt.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# The viewer
|
|
7
|
+
|
|
8
|
+
You can read a node's live conversation, send it more work, interrupt it, search its transcript, and open canvas tools without running another agent process. `crtr surface attach to <node-id>` opens the viewer in the current terminal pane; `crtr surface node focus <node-id>` brings the node's managed viewer into view.
|
|
9
|
+
|
|
10
|
+
The viewer is a client of the broker. Detaching or quitting the viewer leaves the broker running. The default controls below can be changed in `~/.pi/agent/keybindings.json`.
|
|
11
|
+
|
|
12
|
+
## Send a message or interrupt work
|
|
13
|
+
|
|
14
|
+
Type in the editor and press Enter. When the agent is idle, Enter sends a prompt. While it is streaming, Enter sends a steer: an instruction for the current turn. The dedicated follow-up action has no default key binding; if you bind it, it sends a follow-up frame and clears the editor. Use a steer when the current answer needs to change; wait until idle when you want a normal next prompt.
|
|
15
|
+
|
|
16
|
+
Press Escape during a streaming turn to abort it. Press Control+C once to clear the editor. Press it a second time within one second to cancel a streaming turn. When nothing is running, the second Control+C does not cancel anything.
|
|
17
|
+
|
|
18
|
+
## Viewer controls
|
|
19
|
+
|
|
20
|
+
| Key | Action |
|
|
21
|
+
|---|---|
|
|
22
|
+
| Control+D | Detach from the viewer. |
|
|
23
|
+
| Escape | Abort a streaming turn; otherwise use the editor's normal escape behavior. |
|
|
24
|
+
| Control+C | Clear the editor; repeat within one second to cancel a streaming turn. |
|
|
25
|
+
| Control+Z | Suspend the viewer. |
|
|
26
|
+
| Shift+Tab | Cycle the thinking level. |
|
|
27
|
+
| Control+P / Shift+Control+P | Move to the next / previous model. |
|
|
28
|
+
| Control+L | Open the model selector. |
|
|
29
|
+
| Control+O | Toggle tool output. |
|
|
30
|
+
| Control+T | Toggle thinking. |
|
|
31
|
+
| Control+G | Open the external editor. |
|
|
32
|
+
| Alt+Up | Restore queued messages. |
|
|
33
|
+
| Alt+V / Control+V | Paste an image. |
|
|
34
|
+
| Alt+Enter / Shift+Enter | Insert a newline in the editor. |
|
|
35
|
+
| Alt+G | Toggle the canvas graph. |
|
|
36
|
+
| Alt+Shift+K | Open keyboard help. |
|
|
37
|
+
| Alt+U | Jump to pending human requests. |
|
|
38
|
+
| Alt+M / Alt+Shift+M | Select the next / previous model-ladder rung. |
|
|
39
|
+
| Alt+Shift+H | Inspect the loaded slash command. |
|
|
40
|
+
| Alt+Shift+R | Review a transcript file. |
|
|
41
|
+
| Control+F | Search profile files. |
|
|
42
|
+
| Alt+/ | Search the displayed transcript. |
|
|
43
|
+
| Shift+Up / Shift+Down | Scroll one transcript line. |
|
|
44
|
+
| Page Up / Page Down | Scroll one transcript page. |
|
|
45
|
+
| Shift+End | Return to the live end of the transcript. |
|
|
46
|
+
| Alt+Shift+O | Toggle mouse reporting. |
|
|
47
|
+
| Alt+Shift+Y | Copy the newest visible message. |
|
|
48
|
+
|
|
49
|
+
While transcript search is open, press `n` or Shift+`n` for the next or previous match, `/` to edit the query, and Escape to close search.
|
|
50
|
+
|
|
51
|
+
Press Alt+C to open crouter's action menu. Its Attach actions menu offers the same everyday controls: detach, clear or cancel, graph, help, inbox, pending requests, model changes, profile-file search, and transcript search. Alt+] and Alt+[ move to the next and previous node; Alt+I opens the inbox.
|
|
52
|
+
|
|
53
|
+
## Slash commands
|
|
54
|
+
|
|
55
|
+
Type `/` in the editor to see the available commands. These commands are provided by crouter's viewer:
|
|
56
|
+
|
|
57
|
+
| Command | What it opens or changes |
|
|
58
|
+
|---|---|
|
|
59
|
+
| `/clear` | Clear the conversation display. |
|
|
60
|
+
| `/graph` | Open the canvas graph. |
|
|
61
|
+
| `/inbox` | Open the human inbox. |
|
|
62
|
+
| `/promote [kind]` | Promote the current node, optionally selecting a kind. |
|
|
63
|
+
| `/resume` | Open the canvas navigator to choose a node. |
|
|
64
|
+
| `/resume-session [session-path]` | Switch to the supplied saved session file. |
|
|
65
|
+
| `/context` | Open node context and reports. |
|
|
66
|
+
| `/plugins` | Open plugins. |
|
|
67
|
+
| `/node-metadata` | Show node metadata. |
|
|
68
|
+
| `/mcp [server]` | Open MCP controls, optionally for one server. |
|
|
69
|
+
| `/rename <name>` | Rename the current node. |
|
|
70
|
+
| `/color <color\|none>` | Set or clear the node color. |
|
|
71
|
+
| `/mouse` | Toggle mouse support. |
|
|
72
|
+
| `/copy-message` | Copy a message. |
|
|
73
|
+
| `/copy-tool` | Copy tool output. |
|
|
74
|
+
| `/copy-transcript` | Copy the transcript. |
|
|
75
|
+
| `/fold-tools` | Fold or unfold tool output. |
|
|
76
|
+
|
|
77
|
+
The viewer also provides these pi commands: `/settings`, `/model`, `/scoped-models`, `/export`, `/import`, `/share`, `/copy`, `/name`, `/session`, `/changelog`, `/hotkeys`, `/fork`, `/clone`, `/tree`, `/login`, `/logout`, `/new`, `/compact`, `/reload`, and `/quit`. `/quit` detaches the viewer but leaves the shared broker running.
|
|
78
|
+
|
|
79
|
+
Use [Canvas and dashboard](./canvas-and-dashboard.md) when the conversation leads you to another node, and [Human inbox](./human-inbox.md) when the agent needs your answer.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Concepts
|
|
3
|
+
description: When building with crtr, read this section because its pages explain which runtime parts solve each problem before you choose an SDK method or plugin field.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Concepts
|
|
7
|
+
|
|
8
|
+
Use these pages to choose the shape of an agent application before you start wiring it. They explain the durable runtime model behind the SDK and plugin surfaces, then point to the detailed guides for each surface.
|
|
9
|
+
|
|
10
|
+
| Page | Decide |
|
|
11
|
+
|---|---|
|
|
12
|
+
| [Nodes and the canvas](./nodes-and-the-canvas.md) | Whether work needs a durable node rather than one request and response |
|
|
13
|
+
| [Lifecycle and wakes](./lifecycle-and-wakes.md) | Whether a node should finish, remain resident, delegate, or wait |
|
|
14
|
+
| [Memory](./memory.md) | What an agent should know or embody, who owns it, and where it belongs |
|
|
15
|
+
| [Profiles, kinds, and modes](./profiles-kinds-and-modes.md) | Which run-shaping dial matches an application concern |
|
|
16
|
+
| [Scopes and trust](./scopes-and-trust.md) | What an application or node may do and why only the daemon writes canvas state |
|
|
17
|
+
| [Why a daemon](./why-a-daemon.md) | Why a broker survives a terminal and why viewers are clients rather than hosts |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Lifecycle and wakes
|
|
3
|
+
description: When an agent must react to later work, read this because lifecycle and wake choices let it sleep without a process while preserving its goal and the event that should resume it.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Lifecycle and wakes
|
|
7
|
+
|
|
8
|
+
Choose a node’s lifecycle from the kind of relationship it has with work. A **terminal** node owes a final report when it is done. A **resident** node is for an ongoing conversation with a person: it can become dormant and be messaged again without first finalizing. Resident does not mean “keep a process running.” Dormant nodes have no live broker or model turn and cost no context window or compute.
|
|
9
|
+
|
|
10
|
+
Mode answers a different question. A **base** node works hands-on and may delegate a clearly separate piece. An **orchestrator** owns enough independent parallel work that decomposition, delegation, and integration are now its main job. Long or sequential work is not enough reason to orchestrate; keep one hands-on owner and give it a fresh context when needed. Lifecycle answers whether a conversation remains open; mode answers who does the work.
|
|
11
|
+
|
|
12
|
+
```mermaid
|
|
13
|
+
flowchart LR
|
|
14
|
+
Active[Active node] -->|nothing to do now| Dormant[Dormant: no broker]
|
|
15
|
+
Child[Child report] --> Inbox
|
|
16
|
+
Message[Message or human answer] --> Inbox
|
|
17
|
+
Cron[Cron or deadline] --> Inbox
|
|
18
|
+
Inbox -->|wake| Active
|
|
19
|
+
Active -->|terminal final| Finished[Finished]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
A node wakes when work actually arrives: a subscribed child pushes a report, another node or an application sends a message, a person answers a human request, or a cron action delivers work. A deadline is a scheduled wake that races an otherwise unpushable wait. The inbox is the durable path for these triggers, so a node can stop between them without losing its goal.
|
|
23
|
+
|
|
24
|
+
Do not keep a node active to poll a child, a person, or a message. Creation automatically subscribes a parent to its child, and the runtime delivers the child’s outcome. Waiting for something the canvas can push is free: end the turn and let the node become dormant. Schedule a cron only for recurring work or an external condition that nothing can push into the canvas, such as checking a CI run. A timer added “just in case” a child does not report duplicates a runtime guarantee and hides a runtime defect.
|
|
25
|
+
|
|
26
|
+
A broker crash does not erase the node. The daemon retains the durable node row, conversation, waits, and outstanding inbox entries, then applies its recovery policy. This is what makes a resident event-driven assistant practical: it can wait for a webhook, be dormant for hours, and resume its saved work only when the webhook produces a message. Use [`nodes.message`](../sdk/nodes.md#sending-a-follow-up) to deliver that external event, and run `crtr memory read internal/nodes-and-canvas` for lifecycle operations.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Memory
|
|
3
|
+
description: When shaping an agent without rewriting its prompt, read this because memory documents separate facts to consult from behavior to embody and let each owner control who receives them.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory
|
|
7
|
+
|
|
8
|
+
Memory shapes a node without adding the same instructions to every prompt. A memory document says what it contains, who owns it, and when it should enter context. The result is durable guidance that can be discovered when relevant instead of a growing startup prompt.
|
|
9
|
+
|
|
10
|
+
There are two kinds. **Knowledge** is something an agent consults: a procedure, fact, or technical reference. A **preference** is behavior the agent should embody: a standing directive or correction. This is a use-based split. A procedure and a fact are both knowledge because the agent reads either one to answer a question; a preference changes how it acts.
|
|
11
|
+
|
|
12
|
+
| Tier | Owner | Put here |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| Node | One running node | A note needed across that node’s fresh contexts |
|
|
15
|
+
| Project | One repository or workspace | Repository facts and procedures |
|
|
16
|
+
| Profile | One application identity and its purview | Application-wide conventions and knowledge |
|
|
17
|
+
| User | One person | Facts and preferences that follow them everywhere |
|
|
18
|
+
| Builtin | crouter | Runtime documentation that ships to every user |
|
|
19
|
+
|
|
20
|
+
Choose the narrowest tier that reaches the next agent who needs the document. For an application author, the profile store is the usual home for knowledge shared by that application’s nodes across repositories. [`client.memory`](../sdk/memory.md) names a target for every operation, so the daemon resolves the application’s profile rather than its own current directory. A node’s `memory:read` and `memory:write` scopes can respectively permit reading while denying changes.
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
flowchart LR
|
|
24
|
+
Doc[Memory document] --> Surface[Surface entry: event, gate, rung]
|
|
25
|
+
Surface -->|event matches| Preview[Name, preview, or full body]
|
|
26
|
+
Preview --> Route[Routing line tells the agent why to read]
|
|
27
|
+
Route --> Read[Explicit full read when needed]
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
A surface entry is the delivery mechanism. A document is not loaded because it sits in a particular folder or because its routing line resembles the task. Its frontmatter names an event such as boot, workspace-open, file read, memory read, command, or pre-command; that entry can also match a path or gate on the node’s shape and selects a rung: its name, a preview, or its full content. A document with no surface entry stays in its directory listing until an agent deliberately finds or reads it.
|
|
31
|
+
|
|
32
|
+
The routing line is the preview at the middle rung, not a trigger. For example, a profile document can have a file-read surface that delivers a preview when an order record is opened. Its line — “When handling a refund request, read this because the eligibility window is not in the order record” — then tells the agent why an explicit full read is useful. The event delivers the preview; the line helps the agent decide whether to read the body without pretending to replace it.
|
|
33
|
+
|
|
34
|
+
Memory therefore supports progressive disclosure. You can record knowledge freely, but it costs future contexts only when an explicit surface route delivers it. Read `crtr memory write -h` to author a document and `crtr memory read internal/memory-loading` for the routing mechanics. The SDK [memory page](../sdk/memory.md) shows how an application creates and revises its profile documents.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Nodes and the canvas
|
|
3
|
+
description: When deciding whether an agent task should outlive one request, read this because a node gives the task durable identity, context, reports, and a path for later messages.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Nodes and the canvas
|
|
7
|
+
|
|
8
|
+
Use a node when the work may need a follow-up, a report, a child, or time without a caller holding a request open. A node is a durable unit of agent work: it has an identity, a goal, graph relationships, a context directory for artifacts, and a broker that hosts its agent engine. It is not an HTTP request with an LLM response attached.
|
|
9
|
+
|
|
10
|
+
The canvas is the durable graph of those nodes. It makes an agent's work and its relationship to other work visible after the process that created it has returned. This is why [`client.nodes.create`](../sdk/nodes.md) returns a node you can retrieve, message, stream, or wait on instead of only returning generated text. An application can create a root node, show its progress, and later call `nodes.message` when a person or an external event has more work for it.
|
|
11
|
+
|
|
12
|
+
```mermaid
|
|
13
|
+
flowchart TD
|
|
14
|
+
App[Application] -->|creates or messages| Daemon[crtrd]
|
|
15
|
+
Daemon --> Node[Durable node]
|
|
16
|
+
Node --> Broker[Broker and agent engine]
|
|
17
|
+
Node --> Context[Context directory and artifacts]
|
|
18
|
+
Child[Child node] -->|pushes a report| Node
|
|
19
|
+
Node -->|pushes a report| Parent[Subscriber]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
A graph edge is not just a visual parent-child line. The management relationship records who owns a child, while subscriptions carry report delivery. On normal child creation, the parent subscribes to the child, so the child’s final report wakes the parent. A node can have other subscribers too; report delivery is intentionally separate from hierarchy.
|
|
23
|
+
|
|
24
|
+
The one way work reports upward is a **push**. A push writes a durable report and puts a reference in each subscriber’s feed. Nothing is reported merely because a node stopped producing text. That makes a report an explicit claim a subscriber can inspect, rather than an inference from terminal output. The parent can then integrate the child’s result instead of repeating the work.
|
|
25
|
+
|
|
26
|
+
A node owns an outcome, not merely an artifact. It may write files and reports while working, but its terminal result is credible only when it has evidence that the requested goal was met. The canvas supports that responsibility: it preserves the goal, durable artifacts, reports, and relationships across fresh contexts and broker replacement.
|
|
27
|
+
|
|
28
|
+
Use a one-shot SDK call such as [`nodes.parse`](../sdk/nodes.md#parse-and-structured-output) when work is bounded and its only useful output is a typed result. Use `nodes.create` when the application needs a continuing conversation or must observe work while it runs. For the operational graph and report model, run `crtr memory read internal/nodes-and-canvas`.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Profiles, kinds, and modes
|
|
3
|
+
description: When designing an agent run, read this because profiles, kinds, modes, and memory tiers solve different problems and prevent a long prompt from becoming an unstable substitute for an application identity.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Profiles, kinds, and modes
|
|
7
|
+
|
|
8
|
+
Shape a run by choosing the dial that owns the decision. The four dials are independent: a useful profile does not imply an orchestrator, and a specialist kind does not decide where its knowledge lives.
|
|
9
|
+
|
|
10
|
+
| Dial | It answers | Use it when |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Profile | Which application identity, project purview, environment, and profile memory apply? | An application or body of work has stable directories and conventions |
|
|
13
|
+
| Kind | What standing role, model tier, tools, and expertise should the agent have? | The work matches a recurring role such as developer or reviewer |
|
|
14
|
+
| Mode | Does this node work hands-on or coordinate independent children? | Parallel work makes coordination the main job |
|
|
15
|
+
| Memory tier | Who should receive a document? | Guidance must reach one node, project, profile, user, or all crouter users |
|
|
16
|
+
|
|
17
|
+
A profile is not a label on a run. It is a stable agent identity with its own memory store and a purview of project directories. It lets an application create nodes from the same target context even if the caller runs elsewhere. Create a profile when an app has a durable set of directories, environment values, and conventions worth sharing. Do not make a profile for every repository or individual request. Use [`client.profiles`](../sdk/resources.md) and the SDK’s `profile` create field to select the application’s identity.
|
|
18
|
+
|
|
19
|
+
```mermaid
|
|
20
|
+
flowchart LR
|
|
21
|
+
Profile[Profile: purview, environment, memory] --> Node
|
|
22
|
+
Kind[Kind: role and tools] --> Node
|
|
23
|
+
Mode[Mode: base or orchestrator] --> Node
|
|
24
|
+
Tier[Memory tier: reach] --> Node
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
A kind is a recurring role, not a decorative name. It carries a role-specific posture and may choose a suitable model tier and tools. A custom kind beats a long prompt when the role recurs and needs standing discipline that should survive every run: for example, an application’s compliance reviewer that always needs the same tools, expertise, and model choice. A one-off instruction belongs in the node’s prompt, where it does not create a permanent persona to maintain.
|
|
28
|
+
|
|
29
|
+
Base mode is the normal choice: the node owns and performs the work, using a child only for a separable part. Promote to orchestrator only when independent parts can proceed in parallel and the benefits outweigh coordination and integration. A terminal orchestrator still finishes normally; residency is separate and belongs to a person-facing ongoing conversation.
|
|
30
|
+
|
|
31
|
+
These choices keep the application prompt focused. Identity belongs in a profile, standing role in a kind, task-specific intent in the prompt, coordination in mode, and reusable knowledge in the narrowest memory tier. For the full selection rules, run `crtr memory read internal/agent-shaping`; [`nodes.create`](../sdk/nodes.md) documents the profile, kind, and mode fields an application passes.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Scopes and trust
|
|
3
|
+
description: When giving an application or node less authority, read this because a scope list is an allow-list enforced by the daemon and a bearer token can set the maximum authority for every run it creates.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Scopes and trust
|
|
7
|
+
|
|
8
|
+
Use scopes to give a node or remote application only the authority it needs. A node carries a scope list; a scoped bearer token carries a ceiling. Omitting a node scope list gives it the inherited runtime vocabulary. Supplying one narrows that authority. A token cannot create a node with scopes outside its own ceiling.
|
|
9
|
+
|
|
10
|
+
| Scope family | It gates |
|
|
11
|
+
|---|---|
|
|
12
|
+
| `ask` | Human requests and review actions |
|
|
13
|
+
| `act` | Node creation on behalf of a node and node messaging |
|
|
14
|
+
| `schedule` | Creating scheduled work |
|
|
15
|
+
| `memory:read` / `memory:write` | Reading or changing memory through a node target |
|
|
16
|
+
| `llm`, `net`, and parameterized forms such as `files:<dir>` | Declared capability categories; some performers are recorded rather than enforced in the current beta |
|
|
17
|
+
|
|
18
|
+
This is an allow-list, not a claim that code will behave. The daemon checks the scope at the route that performs the action and rejects an unavailable one. The SDK’s [`nodes.create`](../sdk/nodes.md) `scopes` field narrows a run; `client.memory` additionally checks `memory:read` or `memory:write` when you make a request on behalf of a node. A node may be allowed to consult its application’s knowledge while being unable to rewrite it.
|
|
19
|
+
|
|
20
|
+
```mermaid
|
|
21
|
+
flowchart LR
|
|
22
|
+
Token[Bearer token ceiling] --> Request[SDK request]
|
|
23
|
+
Request --> Daemon[crtrd]
|
|
24
|
+
Daemon -->|within ceiling| Node[Node with narrowed scopes]
|
|
25
|
+
Daemon -->|outside ceiling| Denied[403 scope_denied]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Scopes rely on a more basic trust boundary: `crtrd` is the sole writer of durable canvas state and the sole owner of broker lifecycle. SDK clients, the CLI, and viewers call its API; they do not open the canvas database or launch their own broker. One owner serializes lifecycle changes, makes the same API usable locally and remotely, and keeps a client from silently creating a second state authority.
|
|
29
|
+
|
|
30
|
+
For a browser or remote process, run `crtr sys connect`. It enables the daemon’s TCP listener when needed and returns `base_url` plus a bearer `token` to give the application. `crtr sys connect --scopes …` mints a new scoped token instead of returning the owner token. Treat either token as a credential: the remote app sends it as `Authorization: Bearer <token>`, and its scope list is the ceiling for scope-gated calls and newly created nodes.
|
|
31
|
+
|
|
32
|
+
The remote API is an explicit boundary, not permission to reach around it. Keep application code on the SDK or `/v1` contract, and let the daemon own state transitions. Run `crtr memory read internal/nodes-and-canvas` for the operational ownership model.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Why a daemon
|
|
3
|
+
description: When deciding how an application should host or reconnect to an agent, read this because the daemon keeps the durable canvas and broker lifecycle in one place while terminals and SDK clients come and go.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Why a daemon
|
|
7
|
+
|
|
8
|
+
A terminal is not an agent host. A broker is the detached process that hosts one node’s agent engine and session; a viewer is only a terminal presentation attached to that broker. The daemon, `crtrd`, owns the durable canvas and starts, stops, and recovers brokers. This separation lets a node continue after the terminal that created or displayed it has gone away.
|
|
9
|
+
|
|
10
|
+
```mermaid
|
|
11
|
+
flowchart LR
|
|
12
|
+
CLI[crtr CLI] --> API[/v1 API]
|
|
13
|
+
SDK[SDK application] --> API
|
|
14
|
+
Viewer[Terminal viewer] --> API
|
|
15
|
+
API --> Daemon[crtrd]
|
|
16
|
+
Daemon --> Canvas[Canvas state]
|
|
17
|
+
Daemon --> Broker[Detached broker]
|
|
18
|
+
Viewer -. live session .-> Broker
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The broker has one job: host a node’s agent session. The daemon has the broader job: preserve the node graph, state transitions, waits, reports, and broker lifecycle. A viewer may stream a broker’s live session, but it does not become the authority that decides whether that node is active, dormant, or revived. Closing a viewer closes a view, not the node’s durable identity.
|
|
22
|
+
|
|
23
|
+
This is why a process crash is recoverable rather than an automatic loss of work. The daemon retains the node row, session information, artifacts, waits, and inbox state, then applies recovery to the broker execution. A later wake or explicit revival can continue the node’s saved conversation. The application should create nodes through [`client.nodes`](../sdk/nodes.md), not start an LLM process itself, because the daemon is the component that keeps the engine and durable canvas state coordinated.
|
|
24
|
+
|
|
25
|
+
The costs are real. A daemon must be running, and canvas state has one home instead of being scattered across terminals and application processes. Local clients use its owner-only Unix socket. Remote clients use its configured TCP listener and bearer token. A network interruption can therefore fail a mutation loudly rather than encouraging a client to replay it and risk doing the action twice.
|
|
26
|
+
|
|
27
|
+
Those costs buy a simpler model: one state owner, one broker launcher, and clients that can reconnect. A CLI command, an SDK application, and a terminal viewer all use the same API for canvas state. They can come and go without creating competing writers or losing the graph that explains what each agent is doing.
|
|
28
|
+
|
|
29
|
+
For the lower-level runtime model, run `crtr memory read internal/nodes-and-canvas`. For a complete remote application setup, start with the SDK [getting started guide](../sdk/getting-started.md).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.333",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -102,9 +102,9 @@
|
|
|
102
102
|
"test:all": "npm test && npm run test:integration && npm run test:seam"
|
|
103
103
|
},
|
|
104
104
|
"overrides": {
|
|
105
|
-
"@earendil-works/pi-ai": "0.87.
|
|
106
|
-
"@earendil-works/pi-agent-core": "0.87.
|
|
107
|
-
"@earendil-works/pi-tui": "0.87.
|
|
105
|
+
"@earendil-works/pi-ai": "0.87.1",
|
|
106
|
+
"@earendil-works/pi-agent-core": "0.87.1",
|
|
107
|
+
"@earendil-works/pi-tui": "0.87.1"
|
|
108
108
|
},
|
|
109
109
|
"repository": {
|
|
110
110
|
"type": "git",
|
|
@@ -115,10 +115,10 @@
|
|
|
115
115
|
},
|
|
116
116
|
"license": "GPL-3.0-only",
|
|
117
117
|
"dependencies": {
|
|
118
|
-
"@earendil-works/pi-agent-core": "0.87.
|
|
119
|
-
"@earendil-works/pi-ai": "0.87.
|
|
120
|
-
"@earendil-works/pi-coding-agent": "0.87.
|
|
121
|
-
"@earendil-works/pi-tui": "0.87.
|
|
118
|
+
"@earendil-works/pi-agent-core": "0.87.1",
|
|
119
|
+
"@earendil-works/pi-ai": "0.87.1",
|
|
120
|
+
"@earendil-works/pi-coding-agent": "0.87.1",
|
|
121
|
+
"@earendil-works/pi-tui": "0.87.1",
|
|
122
122
|
"cron-parser": "^5.6.0",
|
|
123
123
|
"esbuild": "^0.27.7",
|
|
124
124
|
"proper-lockfile": "4.1.2",
|