@pmndrs/pine 0.0.0-stage → 0.1.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.
Files changed (117) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +180 -2
  3. package/bin/pine.js +27 -0
  4. package/docs/SKILL.md +189 -0
  5. package/docs/references/agents.md +368 -0
  6. package/docs/references/coding.md +126 -0
  7. package/docs/references/configuration.md +229 -0
  8. package/docs/references/events.md +263 -0
  9. package/docs/references/mcp.md +257 -0
  10. package/docs/references/operations.md +280 -0
  11. package/docs/references/overview.md +186 -0
  12. package/docs/references/security.md +489 -0
  13. package/docs/references/setup.md +181 -0
  14. package/docs/references/sources.md +768 -0
  15. package/docs/references/stack.md +105 -0
  16. package/docs/references/tui.md +348 -0
  17. package/examples/home/.env.example +5 -0
  18. package/examples/home/USER.md +4 -0
  19. package/examples/home/agents/main/agent.json +4 -0
  20. package/examples/home/agents/main/workspace/AGENTS.md +14 -0
  21. package/examples/home/agents/main/workspace/MEMORY.md +4 -0
  22. package/examples/home/agents/main/workspace/SOUL.md +4 -0
  23. package/examples/home/models.json +62 -0
  24. package/examples/home/pine.json +30 -0
  25. package/examples/home/skills/README.txt +7 -0
  26. package/examples/launchd/com.pine.daemon.plist +32 -0
  27. package/mcp/browser.d.ts +34 -0
  28. package/mcp/browser.js +228 -0
  29. package/mcp/commands.d.ts +20 -0
  30. package/mcp/commands.js +88 -0
  31. package/mcp/lib.d.ts +13 -0
  32. package/mcp/lib.js +50 -0
  33. package/mcp/web.d.ts +6 -0
  34. package/mcp/web.js +140 -0
  35. package/package.json +32 -4
  36. package/src/agent-admin.d.ts +24 -0
  37. package/src/agent-admin.js +55 -0
  38. package/src/agents.d.ts +343 -0
  39. package/src/agents.js +1587 -0
  40. package/src/cli.d.ts +2 -0
  41. package/src/cli.js +526 -0
  42. package/src/config.d.ts +351 -0
  43. package/src/config.js +514 -0
  44. package/src/dev/claude-model.d.ts +28 -0
  45. package/src/dev/claude-model.js +174 -0
  46. package/src/env-file.d.ts +4 -0
  47. package/src/env-file.js +40 -0
  48. package/src/http.d.ts +46 -0
  49. package/src/http.js +407 -0
  50. package/src/limiter.d.ts +32 -0
  51. package/src/limiter.js +84 -0
  52. package/src/login.d.ts +21 -0
  53. package/src/login.js +126 -0
  54. package/src/manual.d.ts +61 -0
  55. package/src/manual.js +425 -0
  56. package/src/mcp-config.d.ts +40 -0
  57. package/src/mcp-config.js +132 -0
  58. package/src/net.d.ts +36 -0
  59. package/src/net.js +122 -0
  60. package/src/pine.d.ts +32 -0
  61. package/src/pine.js +142 -0
  62. package/src/router.d.ts +56 -0
  63. package/src/router.js +164 -0
  64. package/src/sandbox-fs.d.ts +27 -0
  65. package/src/sandbox-fs.js +172 -0
  66. package/src/security.d.ts +121 -0
  67. package/src/security.js +363 -0
  68. package/src/skills.d.ts +67 -0
  69. package/src/skills.js +163 -0
  70. package/src/source-types.d.ts +61 -0
  71. package/src/source-types.js +1 -0
  72. package/src/sources/command.d.ts +4 -0
  73. package/src/sources/command.js +77 -0
  74. package/src/sources/folder.d.ts +6 -0
  75. package/src/sources/folder.js +116 -0
  76. package/src/sources/ftp.d.ts +4 -0
  77. package/src/sources/ftp.js +307 -0
  78. package/src/sources/http.d.ts +4 -0
  79. package/src/sources/http.js +201 -0
  80. package/src/sources/mqtt.d.ts +18 -0
  81. package/src/sources/mqtt.js +97 -0
  82. package/src/sources/telegram.d.ts +22 -0
  83. package/src/sources/telegram.js +269 -0
  84. package/src/sources/webhook.d.ts +4 -0
  85. package/src/sources/webhook.js +52 -0
  86. package/src/sources.d.ts +339 -0
  87. package/src/sources.js +955 -0
  88. package/src/store.d.ts +89 -0
  89. package/src/store.js +251 -0
  90. package/src/timers.d.ts +83 -0
  91. package/src/timers.js +318 -0
  92. package/src/tools.d.ts +6 -0
  93. package/src/tools.js +777 -0
  94. package/src/tui/app.d.ts +209 -0
  95. package/src/tui/app.js +2223 -0
  96. package/src/tui/client.d.ts +178 -0
  97. package/src/tui/client.js +116 -0
  98. package/src/tui/code-pane.d.ts +51 -0
  99. package/src/tui/code-pane.js +398 -0
  100. package/src/tui/highlight.d.ts +8 -0
  101. package/src/tui/highlight.js +86 -0
  102. package/src/tui/picture.d.ts +141 -0
  103. package/src/tui/picture.js +571 -0
  104. package/src/tui/run.d.ts +8 -0
  105. package/src/tui/run.js +97 -0
  106. package/src/tui/theme.d.ts +32 -0
  107. package/src/tui/theme.js +128 -0
  108. package/src/types.d.ts +124 -0
  109. package/src/types.js +1 -0
  110. package/src/update.d.ts +25 -0
  111. package/src/update.js +110 -0
  112. package/src/util.d.ts +32 -0
  113. package/src/util.js +116 -0
  114. package/src/watching.d.ts +20 -0
  115. package/src/watching.js +68 -0
  116. package/src/workspace-view.d.ts +38 -0
  117. package/src/workspace-view.js +160 -0
@@ -0,0 +1,186 @@
1
+ # How pine works
2
+
3
+ ## The picture
4
+
5
+ You talk to an agent, in the terminal UI or on Telegram. An agent is given four things, each by
6
+ asking it: two that wake it, and two that it uses while it works.
7
+
8
+ ```
9
+ you: terminal UI · Telegram
10
+ │
11
+ ▼
12
+ wake it ┌───────────┐ it uses
13
+ events ───────────────► │ │ ◄───────── MCP servers
14
+ Telegram · MQTT · FTP │ │ ◄───────── skills
15
+ webhooks · folders │ agent │
16
+ web addresses │ │
17
+ commands · etc │ │
18
+ schedules ────────────► │ │
19
+ repeating · once └─────┬─────┘
20
+ │ delegate ──► other agents
21
+ │ subagent ──► with distinct prompts, in parallel
22
+ ▼
23
+ answers · messages · actions
24
+ ```
25
+
26
+ | Given | What it is | Tools | More |
27
+ |---|---|---|---|
28
+ | Events | Something that happens elsewhere wakes the agent: a file arrives, a device reports, a web address changes, you write on Telegram | `add_source`, `subscribe`, `send` | [sources.md](sources.md) |
29
+ | Schedules | The time wakes the agent, with a task: at set times, every so often, or once | `add_schedule` | [events.md](events.md) |
30
+ | MCP servers | Tools from outside that the agent can call | `add_mcp_server` | [mcp.md](mcp.md) |
31
+ | Skills | How something is done, written down once | `add_skill` | [agents.md](agents.md) |
32
+
33
+ Each of the four is set up for the conversation it was asked for in, for the agent, or (by the
34
+ main agent only) for all agents. Only the main agent creates other agents and registers new
35
+ types of event source. See [setup.md](setup.md).
36
+
37
+ How pine itself works is not in an agent's prompt. An agent looks it up with its `manual`
38
+ tool, which searches these pages ([agents.md](agents.md)).
39
+
40
+ ## Inside the daemon
41
+
42
+ Underneath, everything is an event in one log, and three things turn events into work:
43
+ subscriptions, schedules with a task, and routes.
44
+
45
+ ```
46
+ what wakes an agent the daemon model server
47
+ ┌────────────────────────────────┐ ┌──────────────────────────────┐ ┌──────────────────┐
48
+ │ event sources │ │ event log (SQLite) │ │ llama-server or │
49
+ │ telegram a bot, long polling │──►│ topic · payload · trust │ │ any OpenAI-style │
50
+ │ mqtt a broker │ │ │ │ │ endpoint │
51
+ │ folder new, changed files │ │ ▼ │ └────────▲─────────┘
52
+ │ webhook calls from services │ │ subscriptions, schedules │ │
53
+ │ ftp uploads │ │ with a task, and routes │ │ model slots
54
+ │ http an address, polled │ │ when · debounce · throttle │ │ (priority queue)
55
+ │ command run again and again │ │ │ │ │
56
+ │ schedules cron · every · at │ │ │ │ │
57
+ └────────────────────────────────┘ │ ├─ set state │ │
58
+ ▲ │ ├─ publish event │ │
59
+ │ answers, and what │ ├─ one model call ────┼───────────────┤
60
+ │ agents send │ │ │ │
61
+ └────────────────────────┤ └─ agent task │ │
62
+ │ │ │ │
63
+ │ ┌─────────▼────────────┐ │ │
64
+ │ │ task queue (SQLite) │ │ │
65
+ │ │ one lane per session │ │ │
66
+ │ └─────────┬────────────┘ │ │
67
+ │ ┌─────────▼────────────┐ │ │
68
+ │ │ pi session │───┼───────────────┘
69
+ │ │ workspace, AGENTS.md│ │
70
+ │ │ tools, MCP, skills │ │
71
+ │ │ policy gate │ │
72
+ │ └──┬───────────────┬───┘ │
73
+ │ │ delegate │ subagent
74
+ │ ▼ ▼ │
75
+ │ other agents copies of itself
76
+ └──────────────────────────────┘
77
+ ```
78
+
79
+ ## Events
80
+
81
+ Everything that happens is an event. An event has:
82
+
83
+ | Field | Meaning |
84
+ |---|---|
85
+ | `id`, `ts` | Position in the log and time |
86
+ | `topic` | For example `source/telegram/message`, `source/house/message`, `agent/gonzo/done` |
87
+ | `source` | Who published it: `source:<name>` (`source:<name>@<agent>` for an agent's own source), `http`, `api`, `timer`, `route:<name>`, `router`, `agent:<id>`, `approvals`, `pine` |
88
+ | `payload` | Any JSON |
89
+ | `trust` | `owner` or `untrusted`; set by the publisher according to how the content arrived |
90
+ | `cause`, `hops` | The event that led to this one, and how many agent or route steps lie between it and an outside trigger |
91
+ | `reply` | Optional: the topic and fields an answer should be published with |
92
+
93
+ Events are stored in `data/pine.db` and pruned after `limits.eventRetentionDays`. A source can
94
+ report noisy telemetry without storing it.
95
+
96
+ Topics pine itself uses:
97
+
98
+ | Topic | Published when |
99
+ |---|---|
100
+ | `agent/<id>/started`, `agent/<id>/done`, `agent/<id>/failed` | A task starts or ends |
101
+ | `agent/<id>/tool` | A tool call starts or ends (live only, not stored) |
102
+ | `agent/<id>/delta`, `agent/<id>/thinking`, `agent/<id>/message` | Streamed answer text, the start of a thinking phase, the end of a model message with token counts (live only) |
103
+ | `state/<key>` | Shared state changes |
104
+ | `timer/<name>` | A schedule fires (`timer/<name>@<agent>` for an agent's own; `topic` on the schedule overrides it) |
105
+ | `source/<name>/<event>` | An event source reports something (`source/<name>@<agent>/<event>` for an agent's own source) |
106
+ | `out/source/<name>` | An answer on its way out through a source that can send |
107
+ | `hook/<name>` | A hook under `http.hooks` in `pine.json` was called (a `webhook` source reports `source/<name>/received` instead) |
108
+ | `approval/requested`, `approval/decided` | An approval is asked for or answered |
109
+ | `pine/started`, `pine/route-failed` | Daemon lifecycle and route errors |
110
+
111
+ Agents cannot publish on `agent/`, `approval/`, `pine/`, `state/` or `timer/`.
112
+
113
+ ## From event to work
114
+
115
+ Three things start work, and the first two need nothing written by hand:
116
+
117
+ - **A subscription.** An agent subscribes a conversation to an event source (a folder, an MQTT
118
+ device, a web address, a command, a webhook, an FTP drop, Telegram). Each event the source
119
+ reports arrives in that conversation as a message and starts a turn. A source that nobody is
120
+ subscribed to is not running, unless it has `"start": "always"`. See [sources.md](sources.md).
121
+ - **A schedule with a task.** When it is time, the agent is woken with the task, in the
122
+ conversation the schedule belongs to. See [events.md](events.md).
123
+ - **A route.** A rule you write in `pine.json`: it names topic patterns and what to do. It can
124
+ combine the first of these with one of the other two:
125
+ 1. **Rule.** Write shared state (`set`) or publish another event (`publish`). No model.
126
+ 2. **One model call** (`call`). No tools, no history: classify an image, summarise a reading.
127
+ The answer can be published as a new event.
128
+ 3. **Agent turn** (`agent`). A task in an agent's session with its tools.
129
+
130
+ Most events a route handles should stop at 1 or 2. See [events.md](events.md).
131
+
132
+ ## Tasks, sessions, slots
133
+
134
+ A task is a prompt for one agent in one session. Tasks for the same session run one after another;
135
+ different sessions run side by side, limited by `limits.maxConcurrentRuns` model slots. A run
136
+ that only waits (for a delegated task, for sub-agents, for an approval) gives its slot up
137
+ meanwhile, so a chain of agents works even with one slot.
138
+
139
+ A session is a pi `AgentSession`: the model loop, tool calls, compaction and retries are pi's.
140
+ Named sessions are stored as JSONL under `agents/<id>/sessions/<key>/` and survive restarts.
141
+ `"session": "new"` gives a fresh one that is closed when the task ends. A live session is
142
+ closed after `idleMs` without work and resumed from disk when needed. A named session other
143
+ than `main` that is not pinned, not open in a tab of the terminal UI, not subscribed to a
144
+ source and without a schedule of its own is removed after `limits.conversationDays` (7; `0`:
145
+ never) without a message. A run that an outside event started works in a session of its own,
146
+ `<name>~u`, so its history is never shared with yours.
147
+
148
+ When the daemon restarts, queued tasks run; a task that was running is marked failed
149
+ ("interrupted by a daemon restart") because its tool calls may already have had effects.
150
+
151
+ ## Answers
152
+
153
+ When a task ends, pine publishes `agent/<id>/done` or `agent/<id>/failed`. If the task has a
154
+ reply target, the final text is also published there, for example on `out/source/telegram` with
155
+ the chat id, and the Telegram source sends it. An agent that answers exactly `NO_REPLY` (or
156
+ `SILENT`) sends nothing, which is how routine checks stay quiet. A task that failed sends a
157
+ line saying so; a cancelled one sends nothing.
158
+
159
+ ## Agents working together
160
+
161
+ - `delegate` gives another agent a task. That agent runs it in its own workspace with its own
162
+ tools and sees only the task text. By default the caller waits for the answer; with
163
+ `wait: false` the answer arrives later as a message in the caller's session.
164
+ - `subagent` runs several copies of the same agent in parallel, each with its own task and an
165
+ empty context, and returns their final answers. It keeps large searches out of the caller's
166
+ context.
167
+ - Shared state (`state_get`, `state_set`) holds small facts such as `house/mode` that every agent
168
+ can read and that can be shown to an agent in every turn.
169
+ - `publish_event` lets an agent put an event on a topic you allowed, which routes then act on.
170
+ - `send` lets an agent reach out through a source that can send: a message to you on Telegram,
171
+ a command to a device over MQTT.
172
+
173
+ Loops are cut: a delegation chain cannot revisit an agent or exceed
174
+ `limits.maxDelegationDepth`, and events more than `limits.maxEventHops` steps away from an
175
+ outside trigger are not routed.
176
+
177
+ ## Trust
178
+
179
+ How content entered decides what it can do. See [security.md](security.md) for all of it.
180
+
181
+ | Content | Arrives as | Runs with |
182
+ |---|---|---|
183
+ | Your message in the terminal UI or from your paired Telegram account, `pine send`, a schedule (yours, or one an agent made at your wish) | `owner` | The agent's full tool set, in the named session |
184
+ | A webhook, an MQTT message, a new file, handled by a route | `untrusted` | The agent's `untrusted` profile (read-only tools by default), in a separate session |
185
+ | An event of a source a conversation is subscribed to | framed as data; taints that conversation unless the source is marked as yours | The conversation's own tool set, but sending information out needs your approval. With `"separate": true` on the subscription: as the row above |
186
+ | A web page, or the result of an MCP server marked `taints`, read during your own request | taints the session | Full tool set, but sending information out needs your approval |