@agfpd/iapeer 0.2.98 → 0.3.0
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 +21 -7
- package/docs/01-overview.md +86 -0
- package/docs/02-quickstart.md +110 -0
- package/docs/03-peers-runtimes-identity.md +117 -0
- package/docs/04-lifecycle-and-daemon.md +101 -0
- package/docs/05-system-prompt.md +82 -0
- package/docs/06-storage.md +115 -0
- package/docs/07-install-and-update.md +87 -0
- package/docs/08-peer-management.md +119 -0
- package/docs/09-runtimes.md +103 -0
- package/docs/10-messaging.md +69 -0
- package/docs/11-extensions-and-memory.md +60 -0
- package/docs/12-cli-reference.md +96 -0
- package/docs/13-architecture-and-contract.md +190 -0
- package/docs/14-configuration-and-logs.md +91 -0
- package/docs/README.md +97 -0
- package/docs/ru/01-/320/276/320/261/320/267/320/276/321/200.md +86 -0
- package/docs/ru/02-/320/261/321/213/321/201/321/202/321/200/321/213/320/271-/321/201/321/202/320/260/321/200/321/202.md +110 -0
- package/docs/ru/03-/320/277/320/270/321/200/321/213-/321/200/320/260/320/275/321/202/320/260/320/271/320/274/321/213-/320/270/320/264/320/265/320/275/321/202/320/270/321/207/320/275/320/276/321/201/321/202/321/214.md +117 -0
- package/docs/ru/04-/320/266/320/270/320/267/320/275/320/265/320/275/320/275/321/213/320/271-/321/206/320/270/320/272/320/273-/320/270-/320/264/320/265/320/274/320/276/320/275.md +101 -0
- package/docs/ru/05-/321/201/320/270/321/201/321/202/320/265/320/274/320/275/321/213/320/271-/320/277/321/200/320/276/320/274/320/277/321/202.md +82 -0
- package/docs/ru/06-/321/205/321/200/320/260/320/275/320/265/320/275/320/270/320/265.md +115 -0
- package/docs/ru/07-/321/203/321/201/321/202/320/260/320/275/320/276/320/262/320/272/320/260-/320/270-/320/276/320/261/320/275/320/276/320/262/320/273/320/265/320/275/320/270/320/265.md +87 -0
- package/docs/ru/08-/321/203/320/277/321/200/320/260/320/262/320/273/320/265/320/275/320/270/320/265-/320/277/320/270/321/200/320/260/320/274/320/270.md +119 -0
- package/docs/ru/09-/321/200/320/260/320/275/321/202/320/260/320/271/320/274/321/213.md +103 -0
- package/docs/ru/10-/320/276/320/261/320/274/320/265/320/275-/321/201/320/276/320/276/320/261/321/211/320/265/320/275/320/270/321/217/320/274/320/270.md +69 -0
- package/docs/ru/11-/321/200/320/260/321/201/321/210/320/270/321/200/320/265/320/275/320/270/321/217-/320/270-/320/277/320/260/320/274/321/217/321/202/321/214.md +60 -0
- package/docs/ru/12-cli-reference.md +96 -0
- package/docs/ru/13-/320/260/321/200/321/205/320/270/321/202/320/265/320/272/321/202/321/203/321/200/320/260-/320/270-/320/272/320/276/320/275/321/202/321/200/320/260/320/272/321/202.md +190 -0
- package/docs/ru/14-/320/272/320/276/320/275/321/204/320/270/320/263/321/203/321/200/320/260/321/206/320/270/321/217-/320/270-/320/266/321/203/321/200/320/275/320/260/320/273/321/213.md +91 -0
- package/docs/ru/README.md +97 -0
- package/package.json +8 -2
- package/src/cli/index.ts +20 -0
- package/src/tui/onboard/app.tsx +260 -0
- package/src/tui/onboard/run.tsx +72 -0
- package/tsconfig.json +3 -1
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# 12 — CLI
|
|
2
|
+
|
|
3
|
+
[Русский](ru/12-cli-reference.md) · **English**
|
|
4
|
+
|
|
5
|
+
The full list of `iapeer <command>`. General rules: `--help` / `-h` anywhere in the line prints help and runs nothing; flags take both `--key value` and `--key=value` forms.
|
|
6
|
+
|
|
7
|
+
## Core install and maintenance
|
|
8
|
+
|
|
9
|
+
| Command | What it does |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `install` | Core bootstrap: build the `~/.local/bin/iapeer` binary, create the `~/.iapeer/` layout, write the daemon plist (without loading). |
|
|
12
|
+
| `update [version] [--force]` | Update the core from npm, restart the daemon, restart the core's infra services. With no argument — to the latest version; with a version — to the exact one. `--force` reinstalls even when versions match. |
|
|
13
|
+
| `rollback` | Restore the previous binary (`.prev`), restart the daemon, check health. One level back. |
|
|
14
|
+
| `version` · `--version` · `-v` | The installed binary's version. |
|
|
15
|
+
| `help` · `--help` · `-h` | Command help. |
|
|
16
|
+
| `daemon [--install-plist]` | Run the router (normally held by launchd). `--install-plist` only writes the plist, without loading. |
|
|
17
|
+
|
|
18
|
+
`update` checks the daemon's health after the restart: if the daemon didn't revive, the command returns a non-zero code and advises `rollback`.
|
|
19
|
+
|
|
20
|
+
## Host
|
|
21
|
+
|
|
22
|
+
| Command | What it does |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `onboard [flags]` | Host setup: marketplace (Claude + Codex) → notifier → Telegram (human peer) → memory provider. All steps on by default. |
|
|
25
|
+
| `status` | Host snapshot: version, daemon health, memory slot. Non-zero exit code if the daemon is unhealthy. |
|
|
26
|
+
| `install-runtime <runtime> [--package <pkg>] [--npx] [--no-bootstrap]` | Install a runtime package and provision its declared peer set. `--no-bootstrap` — don't load peers into launchd. |
|
|
27
|
+
| `update-runtime <runtime> \| --all [--force]` | Update runtime package(s) with a restart of their peers. |
|
|
28
|
+
|
|
29
|
+
`onboard` flags: `--dry-run` (show without changes), `--no-notifier`, `--no-telegram`, `--no-memory`, `--telegram-human <name>`, `--telegram-user-id <id>`, `--memory <pkg>`, `--infra <list>`.
|
|
30
|
+
|
|
31
|
+
## Peers: creation and review
|
|
32
|
+
|
|
33
|
+
| Command | What it does |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `init [folder] [--runtime r] [--description d] [--bin path] [--no-bootstrap]` | Make the current (or a given) folder a peer: profile, MCP, doctrine. The peer name is the folder name; not set by a separate flag. |
|
|
36
|
+
| `create <name> [--runtime r] [--path folder] [--bin path] [--description d] [--intelligence i] [--no-bootstrap]` | Create a peer from anywhere (by default `~/.iapeer/peers/<name>`) and provision it. |
|
|
37
|
+
| `list [--json]` | The peer registry with per-runtime state. In an interactive terminal — a control panel; otherwise or with `--json` — a table. |
|
|
38
|
+
| `verify [--json] [--fix]` | Check profiles against the standard and registry↔profile divergences. `--fix` self-heals the registry and migrates the old runtime-field format. |
|
|
39
|
+
|
|
40
|
+
## Peers: lifecycle
|
|
41
|
+
|
|
42
|
+
| Command | What it does |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `stop <peer> [runtime] \| --all` | Agent: stop flag + close the session (the daemon won't wake it). Infra: remove from launchd. `--all` — all peers. |
|
|
45
|
+
| `start <peer> [runtime] \| --all` | Clear the stop flag (the session comes up on the first message). Infra: load into launchd. |
|
|
46
|
+
| `new <peer> [runtime]` | An unconditional fresh restart — the emergency lever for a hung/dead session, around the agent. Code 0 = a fresh session is up and ready. |
|
|
47
|
+
| `refresh <peer> [runtime] \| --all` | A lazy "soft restart": an agent peer comes up fresh (re-reads the doctrine/fragments from disk) on its NEXT natural wake. Doesn't kill a live session, doesn't wake the rest, doesn't do an immediate restart — only sets a marker. Routers (notifier/telegram) and absent runtimes are skipped (they have no doctrine). `--all` — all peers. |
|
|
48
|
+
| `remove <peer> [--force]` | Delete the registry entry (doesn't touch the peer's folder). Refuses a live peer without `--force`. Idempotent. |
|
|
49
|
+
| `attach <peer> [runtime]` | Bring up (if asleep), resume the conversation, open the session under the supervisor in the terminal (detach — `Ctrl-]`). |
|
|
50
|
+
| `interrupt <peer> [runtime]` | Interrupt the current turn (Escape), context intact. |
|
|
51
|
+
| `compact <peer> [runtime]` | Compact the conversation; a sleeper is resumed first after idle sleep. |
|
|
52
|
+
| `add-runtime <runtime> (--peer <p> \| --all)` | Add an agent runtime to existing peers. Doesn't touch `default_runtime`. |
|
|
53
|
+
| `default-runtime <runtime> (--peer <p> \| --all)` | Switch the primary runtime (routing / first bring-up). Refuses if the runtime isn't declared. |
|
|
54
|
+
|
|
55
|
+
`stop`/`start`/`new` refuse to touch peers under a foreign launchd plist — the core doesn't intervene in what it doesn't manage.
|
|
56
|
+
|
|
57
|
+
## Messages
|
|
58
|
+
|
|
59
|
+
| Command | What it does |
|
|
60
|
+
|---|---|
|
|
61
|
+
| `send <target> (--message <text> \| --message-file <f\|->) [--from <id>] [--runtime <r>] [--attachment <path>]… [--topic <t>]` | Manual IAP send over the same path as `send_to_peer`. |
|
|
62
|
+
|
|
63
|
+
`--message-file -` reads the body from stdin. `--attachment` is repeatable. `--from` defaults to the current folder's peer identity.
|
|
64
|
+
|
|
65
|
+
## Launch and runtimes
|
|
66
|
+
|
|
67
|
+
| Command | What it does |
|
|
68
|
+
|---|---|
|
|
69
|
+
| `<runtime>` (e.g. `iapeer claude`) | Launch the current folder's peer on this runtime — always as a fresh session. |
|
|
70
|
+
| `connect telegram <peer> [--token <t>]` | Connect a Telegram bot to a peer: register the bot → write into the profile → restart the router. Asks only for the token. |
|
|
71
|
+
|
|
72
|
+
## Extensions and memory
|
|
73
|
+
|
|
74
|
+
| Command | What it does |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `enable <plugin> [peer] [--no-setup]` | Install and enable a capability plugin for a peer (across runtimes), run its setup step. |
|
|
77
|
+
| `native-memory <off\|on> (--peer <p> \| --all)` | Turn off/restore a peer's runtimes' native memory. |
|
|
78
|
+
| `trust-hooks <hooks.json> [--check]` | Pre-trust codex hooks from a file (without the modal). `--check` — a divergence report. |
|
|
79
|
+
|
|
80
|
+
## Agent self-calls
|
|
81
|
+
|
|
82
|
+
Commands an agent runs in its own session (require `PEER_IDENTITY` in the environment):
|
|
83
|
+
|
|
84
|
+
| Command | What it does |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `self-fresh` | Mark itself for a fresh restart and close its session — the daemon brings up a fresh one. |
|
|
87
|
+
| `self-done` | Ephemeral worker: quietly finish, freeing the queue, waking no one. |
|
|
88
|
+
|
|
89
|
+
## Service
|
|
90
|
+
|
|
91
|
+
| Command | What it does |
|
|
92
|
+
|---|---|
|
|
93
|
+
| `daemon` | The router daemon's entry point; launched from the `com.agfpd.iapeer` plist. |
|
|
94
|
+
| `run-infra <name> <runtime>` | An infrastructure peer's entry point; launched from its launchd plist. |
|
|
95
|
+
|
|
96
|
+
These two commands are invoked by launchd, not the operator directly.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# 13 — Architecture and contract
|
|
2
|
+
|
|
3
|
+
[Русский](ru/13-архитектура-и-контракт.md) · **English**
|
|
4
|
+
|
|
5
|
+
A section for those building on iapeer: runtime packages, capability plugins, memory providers.
|
|
6
|
+
|
|
7
|
+
## Invariants
|
|
8
|
+
|
|
9
|
+
The system's behavior rests on these:
|
|
10
|
+
|
|
11
|
+
- **One router.** There's exactly one continuously running daemon in the system. All messages go through it; there's no second router.
|
|
12
|
+
- **Identity per request.** The daemon keeps no client session — it determines who called from the `X-IAPeer-Identity` header of each MCP request. One listener serves all peers.
|
|
13
|
+
- **A single registry writer.** `peers-profiles.json` is written only through one writer under a file lock. Direct writing of the file is forbidden at the core level — this rules out races.
|
|
14
|
+
- **Liveness is defined by a peer's live session.** A peer is alive if and only if it has a live session under the supervisor. This isn't a separate state flag that can desync, but an observable fact.
|
|
15
|
+
- **`delivered` ⟺ landed in a live session.** Delivery success means the message was accepted by a live session (the daemon waited for confirmation). If it didn't confirm — the daemon treats the session as dead rather than lying about success.
|
|
16
|
+
- **The source of truth is the local profile.** The registry is a reprojectable projection of the peer profiles. On a divergence, the profile wins.
|
|
17
|
+
- **The binary is installed on the host.** The daemon runs from the installed `~/.local/bin/iapeer`, not from a source working tree. An update is replacing the binary and restarting the daemon onto it.
|
|
18
|
+
|
|
19
|
+
## Runtime adapters on the core side
|
|
20
|
+
|
|
21
|
+
An adapter is a core layer that knows how to launch a runtime's session. All adapters implement one interface; the runtimes' differences are hidden behind it.
|
|
22
|
+
|
|
23
|
+
The adapter's key properties:
|
|
24
|
+
|
|
25
|
+
- **`kind`** — `tui` (an interactive session that takes input: claude, codex) or `router` (a long-lived process with no input: telegram, notifier).
|
|
26
|
+
- **`usesDoctrine`** — whether the runtime consumes the assembled system prompt. For TUI agents — yes, for routers — no (they aren't language models).
|
|
27
|
+
- **`requiresIntelligence`** — a gate on the peer's nature. For `telegram` it's `natural`: an attempt to give a non-human a Telegram presence is rejected with an explicit error.
|
|
28
|
+
- **`buildArgv`** — how to assemble the launch command: for routers it's `<runtime>-runtime run` plus extra arguments from `launch.env`.
|
|
29
|
+
|
|
30
|
+
Routers skip all the TUI phases: they have no boot dialogs, no readiness markers, no delivery confirmation, no control commands. Their liveness is held by launchd, not a wake by the daemon.
|
|
31
|
+
|
|
32
|
+
The production mechanism for hosting TUI sessions is the **pty supervisor**: a supervisor daemon owns the session's pty and its pane log, and delivery onto input goes through its socket. tmux remains only an internal dev branch (the shadow branch) and doesn't figure at the user level.
|
|
33
|
+
|
|
34
|
+
## The runtime-package contract
|
|
35
|
+
|
|
36
|
+
A runtime package (`*-runtime`) is an npm package that adds an infrastructure runtime. Examples: `@agfpd/notifier-runtime`, `@agfpd/telegram-runtime`.
|
|
37
|
+
|
|
38
|
+
### The runtime.json manifest
|
|
39
|
+
|
|
40
|
+
On self-install the package writes a manifest to `~/.iapeer/runtimes/<runtime>/runtime.json`. The core reads it.
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"runtime": "notifier",
|
|
45
|
+
"version": "0.2.0",
|
|
46
|
+
"selfConfig": { "command": "notifier-runtime", "args": ["self-config"] },
|
|
47
|
+
"peers": [
|
|
48
|
+
{ "personality": "timer", "intelligence": "absent", "description": "Schedule-driven scheduler" },
|
|
49
|
+
{ "personality": "watcher", "intelligence": "absent", "description": "Event watcher" }
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| Field | Type | Required | Purpose |
|
|
55
|
+
|---|---|---|---|
|
|
56
|
+
| `runtime` | string | required | The runtime ID, matches the folder name; pattern `^[a-z][a-z0-9]{0,31}$` |
|
|
57
|
+
| `version` | string | optional | The package version. Used for the gate at `update-runtime`; without it an update simply reinstalls |
|
|
58
|
+
| `selfConfig` | descriptor | optional | A personal-setup hook, called by the core for each peer at provision |
|
|
59
|
+
| `peers` | array | optional | The declared peer set. Present — declared-set mode; absent — operator-add |
|
|
60
|
+
|
|
61
|
+
A `peers[]` element: `personality` (required), `intelligence`, `description`, `path` (an explicit folder), `runtimeBin` (a launcher path) — the last four optional.
|
|
62
|
+
|
|
63
|
+
A **descriptor** (`selfConfig` and the like) is `{ "command": "...", "args": [...] }` or simply a command string.
|
|
64
|
+
|
|
65
|
+
### Two deployment modes
|
|
66
|
+
|
|
67
|
+
- **declared-set** — the manifest contains `peers[]`. `iapeer install-runtime <runtime>` provisions the whole set at once (notifier provisions `timer` and `watcher`).
|
|
68
|
+
- **operator-add** — `peers[]` is empty or absent. Peers are set up by the operator one at a time: `iapeer create <name> --runtime <runtime>` (this is how humans are connected on telegram).
|
|
69
|
+
|
|
70
|
+
### What the core calls on the package
|
|
71
|
+
|
|
72
|
+
The contract is minimal — the core reaches the package in exactly three ways:
|
|
73
|
+
|
|
74
|
+
1. **`npx <package>`** — at install. The package idempotently lays its binary on `PATH` and writes `runtime.json`.
|
|
75
|
+
2. **`<runtime>-runtime run`** — at session launch (via the launchd plist or launch). In the environment — `PEER_PERSONALITY`, `PEER_RUNTIME`, `PEER_IDENTITY`.
|
|
76
|
+
3. **The `selfConfig` hook** — at each peer's provision. Called in the peer's working folder; in the environment — `IAPEER_PEER_PERSONALITY`, `IAPEER_PEER_CWD`, `IAPEER_PEER_RUNTIME`, `IAPEER_PEER_INTELLIGENCE`. Exit code 0 — configured (idempotently), otherwise — an error (the plist is written but not loaded).
|
|
77
|
+
|
|
78
|
+
Commands like `prepare`, `interface`, `bot`, `doctor` are the package's own internal commands for the operator, not a contract with the core: the core doesn't call them.
|
|
79
|
+
|
|
80
|
+
### Install and update
|
|
81
|
+
|
|
82
|
+
- **`install-runtime <runtime>`** determines the npm package (from the built-in registry or the `--package` flag), installs it via `npx`, then provisions the declared peer set.
|
|
83
|
+
- **`update-runtime <runtime>`** compares the manifest version with npm; when behind, it reinstalls, re-provisions, and restarts the runtime's peers with the standard `stop`/`start`.
|
|
84
|
+
|
|
85
|
+
## The capability-plugin standard
|
|
86
|
+
|
|
87
|
+
A capability plugin adds an ability to a peer without being a runtime. The distinction is clear: a runtime is a peer's mode of presence, a plugin is an ability on top of a runtime.
|
|
88
|
+
|
|
89
|
+
### The iapeer.json manifest
|
|
90
|
+
|
|
91
|
+
A plugin may (but need not) place an `iapeer.json` in its root:
|
|
92
|
+
|
|
93
|
+
| Field | Type | Purpose |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `setup` | descriptor | The plugin's setup step. Called at `enable`, if declared and the install succeeded |
|
|
96
|
+
| `requires` | — | Dependencies (runtimes, other plugins). The core doesn't resolve them — the plugin checks them itself and refuses if a dependency is missing |
|
|
97
|
+
|
|
98
|
+
A plugin with no `iapeer.json` or no `setup` is the simple class: it's installed and enabled, with no extra initialization.
|
|
99
|
+
|
|
100
|
+
### enable
|
|
101
|
+
|
|
102
|
+
`iapeer enable <plugin> [peer]`, step by step:
|
|
103
|
+
|
|
104
|
+
1. Finds the peer (by name or by the current folder); refuses if the peer has no agent runtime.
|
|
105
|
+
2. On each of the peer's agent runtimes it installs the plugin: for Claude — into the project scope inside the peer's folder (`plugin install … --scope project`), for Codex — into the host's shared config. The install enables the plugin along the way.
|
|
106
|
+
3. If a `setup` is declared and the install succeeded — it calls it. In the environment: `IAPEER_PEER_PERSONALITY`, `IAPEER_PEER_CWD`; the working folder is the plugin root. The step is best-effort: its failure doesn't roll back the install and enable already done.
|
|
107
|
+
|
|
108
|
+
Idempotency: for Claude the binding is by the peer folder's real path, so a repeated `enable` doesn't disturb other peers or duplicate the install.
|
|
109
|
+
|
|
110
|
+
### iapeer-compatibility criteria
|
|
111
|
+
|
|
112
|
+
A plugin is considered compatible if it:
|
|
113
|
+
|
|
114
|
+
1. is useful on its own;
|
|
115
|
+
2. declares what it provides and what it requires;
|
|
116
|
+
3. doesn't own others' responsibilities;
|
|
117
|
+
4. has an idempotent preparation;
|
|
118
|
+
5. has self-diagnostics (`doctor`/`status`);
|
|
119
|
+
6. uses the shared identity ABI (`PEER_*`) when it's available;
|
|
120
|
+
7. doesn't require the user to manually sync identity between plugins;
|
|
121
|
+
8. understands name, runtime, and identity the same under Claude, Codex, and future runtimes.
|
|
122
|
+
|
|
123
|
+
## The memory-slot contract
|
|
124
|
+
|
|
125
|
+
Memory is provided by a provider that claims the single per-host slot. The slot is occupied by exactly one provider or empty.
|
|
126
|
+
|
|
127
|
+
### The provider manifest
|
|
128
|
+
|
|
129
|
+
The provider atomically writes `~/.iapeer/memory-provider.json`; the core only reads it. Deleting the file frees the slot. The core never writes the slot.
|
|
130
|
+
|
|
131
|
+
```json
|
|
132
|
+
{
|
|
133
|
+
"provider": "iapeer-memory",
|
|
134
|
+
"package": "@agfpd/iapeer-memory",
|
|
135
|
+
"version": "0.2.7",
|
|
136
|
+
"registeredAt": "2026-06-11T17:46:41.449Z",
|
|
137
|
+
"heartbeat": "/Users/me/.iapeer/state/iapeer-memory/memoryd.heartbeat",
|
|
138
|
+
"provision": {
|
|
139
|
+
"command": "/Users/me/.local/bin/iapeer-memory",
|
|
140
|
+
"args": ["provision-peer", "--cwd", "{cwd}", "--runtime", "{runtime}",
|
|
141
|
+
"--personality", "{personality}", "--occasion", "{occasion}"]
|
|
142
|
+
},
|
|
143
|
+
"unprovision": {
|
|
144
|
+
"command": "/Users/me/.local/bin/iapeer-memory",
|
|
145
|
+
"args": ["unprovision-peer", "--cwd", "{cwd}", "--runtime", "{runtime}",
|
|
146
|
+
"--occasion", "{occasion}"]
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
| Field | Type | Required | Purpose |
|
|
152
|
+
|---|---|---|---|
|
|
153
|
+
| `provider` | string | required | The provider name |
|
|
154
|
+
| `package` | string | required | The npm package |
|
|
155
|
+
| `version` | string | required | The package version |
|
|
156
|
+
| `registeredAt` | ISO date | required | When the slot was claimed |
|
|
157
|
+
| `heartbeat` | path | optional | The provider daemon's heartbeat file; `iapeer status` shows its freshness |
|
|
158
|
+
| `provision` | descriptor | optional | The command to set up a peer's memory at birth |
|
|
159
|
+
| `unprovision` | descriptor | optional | The command to wind down at peer removal |
|
|
160
|
+
|
|
161
|
+
`command` must be an absolute path; `args` is an array of strings. The core treats an invalid block as absent, and an empty slot as a normal state.
|
|
162
|
+
|
|
163
|
+
### The provision/unprovision commands
|
|
164
|
+
|
|
165
|
+
Four placeholders are substituted in the arguments (per-argument substitution, at the substring level):
|
|
166
|
+
|
|
167
|
+
| Placeholder | Value |
|
|
168
|
+
|---|---|
|
|
169
|
+
| `{cwd}` | the peer's working folder |
|
|
170
|
+
| `{runtime}` | the specific agent runtime (`claude` / `codex`) |
|
|
171
|
+
| `{personality}` | the peer name — must equal `normalize(basename({cwd}))` (the peer name and folder are 1:1); a mismatch → `ensurePeerProfile` fails |
|
|
172
|
+
| `{occasion}` | the call moment (see below) |
|
|
173
|
+
|
|
174
|
+
**The call moments the core emits:**
|
|
175
|
+
|
|
176
|
+
- **`birth`** — at a peer's birth, one command per agent runtime. It runs after Codex pre-trusts the folder, so the provider's surfaces land in an already-trusted folder.
|
|
177
|
+
- **`remove`** — at a peer's removal, one command per agent runtime. It runs before the peer's state is cleaned — the provider sees it in its last consistent form.
|
|
178
|
+
|
|
179
|
+
**Environment:** the command inherits the whole core environment; the core does **not** add special `IAPEER_PEER_*` here — the provider relies on the placeholders in the arguments. stdin is ignored, stdout/stderr are captured.
|
|
180
|
+
|
|
181
|
+
**Execution semantics:** exit code 0 — success; otherwise — an error; over 120 seconds — a timeout; an unavailable binary — a separate outcome. All best-effort: a command's failure fails neither a peer's birth nor its removal, but is logged loudly. The provider must be idempotent — the core may invoke one command again.
|
|
182
|
+
|
|
183
|
+
### The native-memory lever
|
|
184
|
+
|
|
185
|
+
When the slot is claimed, keeping a runtime's native memory in parallel is harmful. The core, at the birth of a peer with a claimed slot, turns it off:
|
|
186
|
+
|
|
187
|
+
- **Claude** — appends `"autoMemoryEnabled": false` to `<folder>/.claude/settings.json`;
|
|
188
|
+
- **Codex** — appends `[features] memories = false` to `<folder>/.codex/config.toml`.
|
|
189
|
+
|
|
190
|
+
To turn it back on — delete the key (restore the runtime's default). By hand: `iapeer native-memory off|on`. For Codex the core, at birth, also writes folder trust (`[projects."<real-path>"] trust_level = "trusted"`) so the project config is read from the first session; at peer removal this entry is removed.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# 14 — Configuration and logs
|
|
2
|
+
|
|
3
|
+
[Русский](ru/14-конфигурация-и-журналы.md) · **English**
|
|
4
|
+
|
|
5
|
+
The core runs on sensible defaults — no separate setup is needed to start. Behavior is fine-tuned with environment variables; logs give material for analysis when something has gone wrong.
|
|
6
|
+
|
|
7
|
+
## Environment variables
|
|
8
|
+
|
|
9
|
+
All values below are the defaults from the current code. A variable is set in the daemon's environment or a specific peer's (via `launch.env`, see [06 — Storage](06-storage.md)).
|
|
10
|
+
|
|
11
|
+
### Lifecycle
|
|
12
|
+
|
|
13
|
+
| Variable | Default | What it sets |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `IAPEER_IDLE_SECS` | `3600` | After how many idle seconds the daemon closes an agent session (sleep). |
|
|
16
|
+
| `IAPEER_BOOT_DEADLINE_SECS` | `240` | How long to wait for a session to load on bring-up before treating the launch as failed. |
|
|
17
|
+
| `IAPEER_READY_GATE_SECS` | `120` | How long to wait for the agent to be ready for input after load. |
|
|
18
|
+
| `IAPEER_CRASHLOOP_MAX` | `3` | How many deaths in the window are allowed before the daemon stops bringing the peer up. |
|
|
19
|
+
| `IAPEER_CRASHLOOP_WINDOW_SECS` | `300` | The window (seconds) over which deaths are counted for restart-loop protection. |
|
|
20
|
+
| `IAPEER_EPHEMERAL_QUIET_SECS` | `20` | The quiet window after which an ephemeral worker that already replied winds down. |
|
|
21
|
+
| `IAPEER_EPHEMERAL_UNARMED_IDLE_SECS` | `600` | The safety bound for an ephemeral worker that stays silent and sent no reply. |
|
|
22
|
+
|
|
23
|
+
The daemon's supervisory tick is fixed — once a minute, not configurable.
|
|
24
|
+
|
|
25
|
+
### Daemon
|
|
26
|
+
|
|
27
|
+
| Variable | Default | What it sets |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| `IAPEER_PORT` | `8765` | The router's TCP port on `127.0.0.1`. |
|
|
30
|
+
| `IAPEER_DAEMON_SOCKET` | `~/.iapeer/state/iapeer/router.sock` | The daemon's local socket path. |
|
|
31
|
+
| `IAPEER_BEARER_TOKEN` | — | If set, the daemon requires this bearer token at the entrance; otherwise token checking is off. |
|
|
32
|
+
|
|
33
|
+
### Message delivery
|
|
34
|
+
|
|
35
|
+
| Variable | Default | What it sets |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `IAP_HOST_LIVENESS_GRACE_MS` | `4000` | How long to wait for confirmation that a session accepted a message before treating it as dead. |
|
|
38
|
+
| `IAP_LIVENESS_GRACE_MS` | `3000` | The liveness-check window for a busy session (by the conversation-history shift). |
|
|
39
|
+
| `IAPEER_COMPOSER_QUEUE_TIMEOUT_MS` | `120000` | How long the composer queue waits for the input field to free before force-delivering. |
|
|
40
|
+
| `IAPEER_COMPOSER_QUEUE_POLL_MS` | `500` | The poll frequency of the input field in the composer queue. |
|
|
41
|
+
|
|
42
|
+
### Paths and binaries
|
|
43
|
+
|
|
44
|
+
| Variable | Default | What it sets |
|
|
45
|
+
|---|---|---|
|
|
46
|
+
| `IAPEER_ROOT` | `~/.iapeer` | The storage root. Changing it isolates sockets into `<root>/socks` (useful for isolated test hosts). |
|
|
47
|
+
| `IAPEER_SOCK_DIR` | `/tmp` | The host-wide socket directory. Overrides the host-wide location. |
|
|
48
|
+
| `IAPEER_BIN_DIR` | `~/.local/bin` | Where the `iapeer` binary is installed. |
|
|
49
|
+
| `IAPEER_LAUNCHAGENTS_DIR` | `~/Library/LaunchAgents` | The launchd plists directory. |
|
|
50
|
+
| `IAPEER_CLAUDE_BIN` | `~/.local/bin/claude` | The path to the Claude binary. |
|
|
51
|
+
| `IAPEER_CODEX_BIN` | `codex` (from `PATH`) | The path to the Codex binary. |
|
|
52
|
+
| `NOTIFIER_RUNTIME_BIN` | `notifier-runtime` (from `PATH`) | The path to the notifier launcher (for launchd with its minimal `PATH`). |
|
|
53
|
+
| `TELEGRAM_RUNTIME_BIN` | `telegram-runtime` (from `PATH`) | The path to the Telegram launcher. |
|
|
54
|
+
| `CODEX_HOME` | `~/.codex` | An override for Codex's global config directory. |
|
|
55
|
+
|
|
56
|
+
### Logs
|
|
57
|
+
|
|
58
|
+
| Variable | Default | What it sets |
|
|
59
|
+
|---|---|---|
|
|
60
|
+
| `IAPEER_LIFECYCLE_LOG_MAX_BYTES` | `5 MiB` | The `lifecycle.log` size at which rotation happens. |
|
|
61
|
+
| `IAPEER_LIFECYCLE_LOG_KEEP` | `5` | How many `lifecycle.log` rotations to keep. |
|
|
62
|
+
| `IAPEER_DELIVERY_LOG_MAX_BYTES` | `5 MiB` | The `delivery.log` size for rotation. |
|
|
63
|
+
| `IAPEER_DELIVERY_LOG_KEEP` | `5` | How many `delivery.log` rotations to keep. |
|
|
64
|
+
| `IAPEER_SUPERVISE_LOG_VERBOSE` | off | A verbose log of supervisory ticks (by default only decisions are written, not routine "doing nothing"). |
|
|
65
|
+
| `IAPEER_DAEMON_LOG` | off | An extended daemon log. |
|
|
66
|
+
|
|
67
|
+
### Internal, dev, and test
|
|
68
|
+
|
|
69
|
+
`IAPEER_TEST_SANDBOX=1` turns on write protection for real paths: the install refuses to write into the real `~/.local/bin/iapeer` and requires `IAPEER_BIN_DIR` set to an isolated path. For development and automated tests, not for normal work.
|
|
70
|
+
|
|
71
|
+
A few more variables the system reads but that aren't set in normal operation:
|
|
72
|
+
|
|
73
|
+
- `NOTIFIER_FALLBACK_TARGET` — a fallback recipient for notifier signals; the core resolves it into the peer's plist at onboarding (no hardcode), the operator doesn't set it by hand.
|
|
74
|
+
- `IAP_TMUX_PASTE_SETTLE_MS`, `IAP_TMUX_SUBMIT_TIMEOUT_MS` — delivery timings in the internal tmux dev branch; production uses the pty supervisor ([13 — Architecture and contract](13-architecture-and-contract.md)), so they aren't needed outside development.
|
|
75
|
+
- `IAPEER_SHADOW_PATH` — the `PATH` for a shadow-fidelity run (an internal development tool).
|
|
76
|
+
|
|
77
|
+
## Logs and diagnostics
|
|
78
|
+
|
|
79
|
+
The daemon keeps three durable logs in `~/.iapeer/logs/iapeer/`:
|
|
80
|
+
|
|
81
|
+
- **`lifecycle.log`** — lifecycle decisions: wakes, sleeps, restarts, supervisory-tick outcomes. The first place to look if a peer is behaving wrong.
|
|
82
|
+
- **`delivery.log`** — the outcome of each delivery: who, to whom, into which runtime, the result, sizes, topic. Metadata only — **the message body is not written**.
|
|
83
|
+
- **`exits.log`** — session deaths with postmortem data: the supervisor records the cause (exit code / signal) at the moment a session dies.
|
|
84
|
+
|
|
85
|
+
### Postmortem diagnostics
|
|
86
|
+
|
|
87
|
+
The cause of a session's death (exit code / signal) the supervisor records at the moment of death — what an ordinary "is the process alive" check misses. A separate canary holds a connection to the supervisor and, on a session's death, writes the circumstances to `exits.log`: memory, swap, top processes by consumption, system diagnostic reports. It's the material for answering "why did the agent die".
|
|
88
|
+
|
|
89
|
+
### Full Disk Access
|
|
90
|
+
|
|
91
|
+
To read system diagnostic reports, the `iapeer` binary needs Full Disk Access (FDA) — a macOS permission. `iapeer status` shows whether FDA is granted and hints at what to do if not. Without FDA, peers will hit TCC prompts when accessing protected folders and third-party app containers.
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# iapeer
|
|
2
|
+
|
|
3
|
+
[Русский](ru/README.md) · **English**
|
|
4
|
+
|
|
5
|
+
iapeer is the core of a multi-agent system on one host. It maintains a registry of participants, a single router daemon for messaging between them, and a set of commands to manage participants: create, start, sleep, restart, connect to external channels.
|
|
6
|
+
|
|
7
|
+
A participant in the system is called a **peer**. A peer can be an AI agent (Claude, Codex), a human (over Telegram), or a service process (a scheduler, a watcher). iapeer doesn't distinguish them by nature at the transport level — they're all addressed the same way and exchange messages over one protocol.
|
|
8
|
+
|
|
9
|
+
```text
|
|
10
|
+
send_to_peer (from any peer)
|
|
11
|
+
│
|
|
12
|
+
▼
|
|
13
|
+
┌────────────────────────┐
|
|
14
|
+
│ router daemon │ runs continuously
|
|
15
|
+
│ find · deliver │ reads peers-profiles.json (the registry)
|
|
16
|
+
└────────────────────────┘
|
|
17
|
+
│
|
|
18
|
+
▼
|
|
19
|
+
recipient peer (asleep? it'll be brought up)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## What it solves
|
|
23
|
+
|
|
24
|
+
When a machine hosts not one agent but a team — each with its own role, working folder, and runtime — problems arise that a single agent doesn't have:
|
|
25
|
+
|
|
26
|
+
- **Addressing.** How agent A sends a message to agent B without knowing whether B is running right now.
|
|
27
|
+
- **Presence.** Whether to keep every agent in memory all the time (expensive) or bring them up on demand (someone has to do the bringing up).
|
|
28
|
+
- **Identity.** The same logical agent may be present in different runtimes (Claude today, Codex tomorrow) — the system must understand it's the same peer.
|
|
29
|
+
- **Lifecycle.** Who sleeps an idle agent, who restarts a hung one, who keeps a crashed agent from entering a restart loop.
|
|
30
|
+
|
|
31
|
+
iapeer takes this on. An agent only needs to call `send_to_peer(<name>, <text>)` — the daemon does the rest: finds the recipient in the registry, checks whether it's alive, delivers into a live session or brings up a sleeper and delivers after the wake.
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
Requirements: **macOS** (process management goes through launchd), **[bun](https://bun.sh)** on `PATH`, and at least one agent runtime — Claude Code or Codex CLI.
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# 1. Install the core — the binary, the ~/.iapeer layout, and the daemon plist
|
|
39
|
+
npx @agfpd/iapeer
|
|
40
|
+
|
|
41
|
+
# 2. Set up the host — onboard starts the daemon, registers the marketplace,
|
|
42
|
+
# installs notifier, Telegram, and memory
|
|
43
|
+
iapeer onboard
|
|
44
|
+
|
|
45
|
+
# 3. Create your first agent
|
|
46
|
+
iapeer create assistant --runtime claude
|
|
47
|
+
|
|
48
|
+
# 4. Send a message — the daemon brings up the session if there's none
|
|
49
|
+
iapeer send assistant --message "hi, are you there?"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
A detailed breakdown of each step — in [02 — Quick start](02-quickstart.md).
|
|
53
|
+
|
|
54
|
+
## Documentation
|
|
55
|
+
|
|
56
|
+
The sections are layered: from "install and use" to "understand the architecture and extend it".
|
|
57
|
+
|
|
58
|
+
**Introduction**
|
|
59
|
+
- [01 — Overview](01-overview.md) — what iapeer is and what it's made of
|
|
60
|
+
- [02 — Quick start](02-quickstart.md) — install, onboarding, the first peer, the first message
|
|
61
|
+
|
|
62
|
+
**Concepts**
|
|
63
|
+
- [03 — Peers, runtimes, identity](03-peers-runtimes-identity.md)
|
|
64
|
+
- [04 — Lifecycle and the daemon](04-lifecycle-and-daemon.md)
|
|
65
|
+
- [05 — Identity and the system prompt](05-system-prompt.md)
|
|
66
|
+
- [06 — Storage](06-storage.md)
|
|
67
|
+
|
|
68
|
+
**Guides**
|
|
69
|
+
- [07 — Install and update](07-install-and-update.md)
|
|
70
|
+
- [08 — Peer management](08-peer-management.md)
|
|
71
|
+
- [09 — Runtimes](09-runtimes.md)
|
|
72
|
+
- [10 — Messaging](10-messaging.md)
|
|
73
|
+
- [11 — Extensions and memory](11-extensions-and-memory.md)
|
|
74
|
+
|
|
75
|
+
**Reference**
|
|
76
|
+
- [12 — CLI](12-cli-reference.md) — all commands with flags
|
|
77
|
+
- [13 — Architecture and contract](13-architecture-and-contract.md) — for plugin and runtime-package developers
|
|
78
|
+
- [14 — Configuration and logs](14-configuration-and-logs.md) — environment variables, logs, diagnostics
|
|
79
|
+
|
|
80
|
+
## Status
|
|
81
|
+
|
|
82
|
+
Built and working: the single router daemon, the messaging protocol (IAP), the peer registry, identity and its ABI, the lifecycle (wake, sleep, restart, supervision), runtime adapters for Claude, Codex, Telegram, and notifier, host install and onboarding, Telegram connection, the memory slot, and capability plugins.
|
|
83
|
+
|
|
84
|
+
Planned on top of the core: a package-compatibility graph, a whole-team health doctor, and an interactive coordination interface. Until those exist, coordination operations live in the `iapeer` CLI.
|
|
85
|
+
|
|
86
|
+
## Roadmap
|
|
87
|
+
|
|
88
|
+
Larger directions, planned and not yet built:
|
|
89
|
+
|
|
90
|
+
- **Web UI** — a browser interface for working with the team.
|
|
91
|
+
- **Linux support** — iapeer runs on macOS today; Linux is planned.
|
|
92
|
+
- **More agent runtimes** — `opencode` and `antigravity`, two further CLI runtimes alongside Claude Code and Codex.
|
|
93
|
+
- **Discord runtime** — a human-presence runtime for Discord, alongside Telegram.
|
|
94
|
+
- **Permissions gate** — finer control over what an agent is allowed to do.
|
|
95
|
+
- **Approve permissions over Telegram** — approve an agent's permission requests from the chat; today permissions are auto-allowed by flags.
|
|
96
|
+
|
|
97
|
+
The platform for now is macOS/launchd only. Linux (systemd) and Windows support is not implemented.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# 01 — Обзор
|
|
2
|
+
|
|
3
|
+
**Русский** · [English](../01-overview.md)
|
|
4
|
+
|
|
5
|
+
iapeer держит команду агентов на одном хосте: ведёт реестр участников, маршрутизирует сообщения между ними и управляет их присутствием. Три понятия задают всю систему — пир, рантайм, идентичность.
|
|
6
|
+
|
|
7
|
+
## Пир
|
|
8
|
+
|
|
9
|
+
Пир — участник системы. Это AI-агент (Claude, Codex), человек (через Telegram) или служебный процесс (планировщик, наблюдатель). На уровне транспорта они неразличимы: адресуются одинаково, обмениваются сообщениями по одному протоколу.
|
|
10
|
+
|
|
11
|
+
У пира есть имя (`personality`) — короткое логическое имя в нижнем регистре (`assistant`, `code-reviewer`). Имя стабильно при переходе между рантаймами, выводится из имени рабочей папки и уникально: два пира одно имя носить не могут.
|
|
12
|
+
|
|
13
|
+
Природу пира задаёт атрибут `intelligence` — он едет в конверте каждого сообщения, поэтому получатель знает, с кем говорит, без внешних договорённостей:
|
|
14
|
+
|
|
15
|
+
| Значение | Кто |
|
|
16
|
+
|---|---|
|
|
17
|
+
| `artificial` | AI-агент (Claude, Codex) |
|
|
18
|
+
| `natural` | человек (через Telegram) |
|
|
19
|
+
| `absent` | программа без интеллекта (планировщик, наблюдатель) |
|
|
20
|
+
|
|
21
|
+
## Рантайм
|
|
22
|
+
|
|
23
|
+
Рантайм — способ присутствия пира. Один пир может присутствовать в нескольких рантаймах. По управлению жизненным циклом рантаймы делятся на два класса:
|
|
24
|
+
|
|
25
|
+
- **claude, codex** — AI-агенты. Сессию не держат запущенной постоянно: демон поднимает агента на входящее сообщение и закрывает сессию после часа простоя. Этим классом распоряжается демон.
|
|
26
|
+
- **telegram, notifier** — служебные рантаймы-роутеры (не AI). Работают постоянно: Telegram-мост принимает входящие в любой момент, notifier срабатывает по расписанию. Их держит launchd с автоперезапуском. Эти рантаймы называются инфраструктурными; демон их не трогает.
|
|
27
|
+
|
|
28
|
+
Граница — это разделение ответственности: демон управляет агентами claude/codex, launchd — инфраструктурными рантаймами. Команды `stop`/`start`/`new` поэтому работают по-разному в зависимости от класса.
|
|
29
|
+
|
|
30
|
+
## Идентичность
|
|
31
|
+
|
|
32
|
+
Идентичность — адрес живого присутствия пира, склейка рантайма и имени:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
PEER_IDENTITY = PEER_RUNTIME + "-" + PEER_PERSONALITY
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Агент `assistant` в Claude — `claude-assistant`, он же в Codex — `codex-assistant`: имя одно, идентичности разные. Разбор идёт по первому дефису (в имени рантайма дефисов нет, в имени пира допустимы), поэтому `claude-code-reviewer` — это рантайм `claude` и пир `code-reviewer`.
|
|
39
|
+
|
|
40
|
+
Три значения — `PEER_PERSONALITY`, `PEER_RUNTIME`, `PEER_IDENTITY` — передаются в окружение сессии. По ним любой компонент знает своё имя и от чьего лица действует. Подробно — [03 — Пиры, рантаймы, идентичность](03-пиры-рантаймы-идентичность.md).
|
|
41
|
+
|
|
42
|
+
## Компоненты
|
|
43
|
+
|
|
44
|
+
```text
|
|
45
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
46
|
+
│ CLI iapeer <команда> │
|
|
47
|
+
│ create · list · send · stop/start · new · connect · enable … │
|
|
48
|
+
└───────────────┬──────────────────────────────────────────────┘
|
|
49
|
+
│
|
|
50
|
+
┌───────────────▼───────────────┐ ┌──────────────────────────┐
|
|
51
|
+
│ Демон-роутер (работает 24/7) │ │ Реестр пиров │
|
|
52
|
+
│ • принимает send_to_peer │◀───▶│ ~/.iapeer/ │
|
|
53
|
+
│ • находит получателя │ │ peers-profiles.json │
|
|
54
|
+
│ • доставляет / поднимает │ └──────────────────────────┘
|
|
55
|
+
│ • надзор за пирами │
|
|
56
|
+
└───────────────┬───────────────┘
|
|
57
|
+
│ поднимает / усыпляет
|
|
58
|
+
┌───────────────▼───────────────────────────────────────────────┐
|
|
59
|
+
│ Рантайм-адаптеры │
|
|
60
|
+
│ claude · codex (pty-супервизор) │ telegram · notifier (launchd)│
|
|
61
|
+
└────────────────────────────────────────────────────────────────┘
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Демон-роутер** — единственный постоянно работающий процесс ядра, под launchd. Принимает вызовы `send_to_peer`, находит получателя в реестре, доставляет сообщение в живую сессию или поднимает спящего агента. Раз в минуту обходит пиров: закрывает сессии после часа простоя, перезапускает помеченных на свежий старт, не даёт упавшему агенту войти в цикл перезапусков. См. [04 — Жизненный цикл и демон](04-жизненный-цикл-и-демон.md).
|
|
65
|
+
|
|
66
|
+
**Реестр пиров** — `~/.iapeer/peers-profiles.json`: имя, рантаймы, описание, природа, рабочая папка каждого пира. Источник истины — профиль каждого пира (`<папка>/.iapeer/peer-profile.json`); реестр пересобирается из профилей. См. [06 — Хранение](06-хранение.md).
|
|
67
|
+
|
|
68
|
+
**Рантайм-адаптеры** — слой запуска сессий. Для Claude и Codex это TUI-сессия под pty-супервизором с подменённым системным промптом; для Telegram и notifier — долгоживущий процесс-роутер под launchd. Адаптеры прячут различия рантаймов за единым интерфейсом. См. [09 — Рантаймы](09-рантаймы.md).
|
|
69
|
+
|
|
70
|
+
**CLI `iapeer`** — вход для оператора и агентов: создание пиров, обзор и состояние пиров, ручная отправка, остановка и перезапуск, подключение Telegram, установка расширений. См. [12 — CLI](12-cli-reference.md).
|
|
71
|
+
|
|
72
|
+
## Путь сообщения
|
|
73
|
+
|
|
74
|
+
1. Отправитель вызывает `send_to_peer(assistant, "...")` — вызов идёт в демон по локальному сокету или HTTP.
|
|
75
|
+
2. Демон находит `assistant` в реестре и проверяет наличие живой сессии.
|
|
76
|
+
3. **Жив** — сообщение вставляется в сессию, демон подтверждает приём, отвечает `доставлено`.
|
|
77
|
+
4. **Спит** — демон поднимает сессию (продолжает прежний диалог или начинает свежий), доставляет, отвечает `доставлено, разбудил`.
|
|
78
|
+
5. **Остановлен** оператором — демон отказывает в доставке и сообщает отправителю прямо.
|
|
79
|
+
|
|
80
|
+
Ответ `доставлено` означает, что сообщение легло в живую сессию, — очереди «на потом» в обычном случае нет. Механику разбирает [10 — Обмен сообщениями](10-обмен-сообщениями.md).
|
|
81
|
+
|
|
82
|
+
## Дальше
|
|
83
|
+
|
|
84
|
+
- Попробовать — [02 — Быстрый старт](02-быстрый-старт.md).
|
|
85
|
+
- Понять понятия глубже — [03 — Пиры, рантаймы, идентичность](03-пиры-рантаймы-идентичность.md).
|
|
86
|
+
- Разработать расширение или рантайм-пакет — [13 — Архитектура и контракт](13-архитектура-и-контракт.md).
|