Skip to content

Commit 75a7244

Browse files
ndemiancclaude
andcommitted
Atom++ Agent Sketch: run persistence + prompt-to-flow + connector archetypes
Never lose a paid run: - sketch.js writeSession/readSession (atomic) + init restore; the webview autosaves the whole session (graph + last-run results) to .atompp/.session.json on every mutation (debounced) and immediately on run completion / clear, and restores it on reopen. nodeDone now carries FULL output (not a 400-char preview) so a mid-run/interrupted run never persists truncated text; restore keeps unknown-agent nodes so an extension update can't wipe a run. Export button → a Markdown deliverable. Design + free-vs-paid cloud-sync monetization: docs/atompp-agent-runs-persistence.md. Prompt -> whole flow: - Empty board + a description → generateFlow() designs a complete DAG (populated board still edits via ops). normalizeFlowSpec resolves edges by the model's own labels (first-declared wins; dedup labels it never saw aren't registered) and accepts 1-based index refs, so fan-in/out isn't miswired. - agentCatalog.js: +2 groups (Content & Editorial, Connectors & Triggers) and 13 archetypes (news-collector, press-editor, copywriter, telegram-publisher, email-sender, scheduler, …). SK1 runs them text-only (a connector emits the payload it WOULD send); real side effects + cron = SK2/SK3, designed in docs/atompp-agent-sketch-design.md §4. .gitignore: ignore /.atompp/ (per-workspace runtime state) and local /UNSIGNED-*.app.zip artifacts. Hardened via three adversarial-review passes (Clear TOCTOU, persistence data-loss x3, generator edge-wiring x4) — all fixed. 75 unit tests green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent cf629c8 commit 75a7244

6 files changed

Lines changed: 708 additions & 11 deletions

File tree

‎.gitignore‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
# Distributable disk images (produced by scripts/make-dmg.sh)
1111
/*.dmg
1212

13+
# Agent Sketch runtime state — per-workspace (autosaved session, sketches, exported runs); not source
14+
/.atompp/
15+
16+
# Unsigned app artifacts pulled from the release CI and signed locally (see docs/RELEASING.md §7)
17+
/UNSIGNED-*.app.zip
18+
1319
# Node / OS noise
1420
node_modules/
1521
.DS_Store
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# Atom++ — Agent Run Persistence → Cloud Sync (design + monetization)
2+
3+
> **Status:** free local baseline **shipped** (SK1.2) · cloud sync **designed, not built**
4+
> **Date:** 2026-07-02 · **Owner:** Sergii Demianchuk
5+
> **One line:** an agentic run costs real money; losing it on a reload is unacceptable. Make local
6+
> durability **free and automatic**, and sell the **cloud layer** (cross-device sync, a durable
7+
> searchable run archive, cost analytics, team sharing) — never inference. This stays true to
8+
> Atom++'s BYOK-primary rule: [[atompp-cloud-byok-primary]].
9+
10+
---
11+
12+
## 1. The problem
13+
14+
Agent Sketch (and the chat agent) can burn **real, user-billed tokens** on a long multi-agent run —
15+
the "Design a Key-Value Store" template alone is 11 agents, easily dollars per run. Yet the run's
16+
value — every node's **output text, token counts, and cost** — lived only in the webview's memory
17+
(`outputsByNode` / `usageByNode`). Worse, an *unsaved* sketch's **graph** was also memory-only. So:
18+
19+
> Build a flow → run it (spend $2) → reopen the folder (or the window reloads) → **the graph and
20+
> every result are gone.** The money is spent; the work is not recoverable.
21+
22+
`retainContextWhenHidden` survives a tab-hide, **not** a window/folder reload. This is the single
23+
most trust-damaging failure mode in the feature, and it's the natural wedge for a sync subscription —
24+
but only if we get the free/paid line right (§4).
25+
26+
---
27+
28+
## 2. The free local baseline (shipped)
29+
30+
**Principle: durability of your own machine's work is free and automatic. Never paywall "don't lose
31+
my file."** Paywalling that reads as hostile and poisons the paid story.
32+
33+
### 2.1 Session autosave + restore
34+
- The webview bundles the whole session — `{name, goal, nodes, edges, results:{outputs, usage,
35+
turns, trunc}}` — via `fullSession()` and posts a debounced `persist` message. Every mutation
36+
flows through `render()`, so autosave is automatic; drags/typing coalesce into one write (800 ms
37+
debounce). Run **results** persist immediately on `runDone` (`persistNow()`), and a **cleared**
38+
canvas persists immediately too (so a reopen doesn't resurrect a deleted graph).
39+
- The extension writes it to **`.atompp/.session.json`** with an atomic temp-write + rename, so a
40+
crash mid-write can't corrupt it. Best-effort: persistence never throws into a run.
41+
- On panel reopen, the extension ships the saved session in the `init` message; the webview
42+
`restoreSession()` repopulates the canvas **and** the per-node meters/outputs, then fits the view
43+
and drops an Activity entry: *"Restored your last session (with run results)."* Results are kept
44+
only for **surviving node ids**, so a hand-edited/renamed graph can't graft stale outputs.
45+
- Autosave is armed (`persistReady`) only **after** the restore, so the initial empty render can't
46+
clobber the saved session.
47+
48+
### 2.2 On-demand Markdown export
49+
A **Export** button renders the current run as a readable `.md` (goal, totals, then each agent's
50+
model/tokens/cost + full output) into `.atompp/runs/<name>-<ts>.md` and opens it. This is the
51+
"share it / drop it in a PR / paste to a teammate" deliverable.
52+
53+
### 2.3 What is deliberately **not** free
54+
Cross-device sync, an unlimited/searchable archive, and cost analytics — see §4/§5.
55+
56+
---
57+
58+
## 3. Data model
59+
60+
`fullSession()` / `.atompp/.session.json` (and the future cloud "run record"):
61+
62+
```jsonc
63+
{
64+
"name": "Design a Key-Value Store",
65+
"goal": "Build ... in C",
66+
"nodes": [{ "id": "n1", "agentId": "planner", "label": "requirements",
67+
"instructions": "...", "model": "", "x": 60, "y": 60 }, ...],
68+
"edges": [{ "from": "n1", "to": "n2" }, ...],
69+
"results": {
70+
"outputs": { "n1": "<full text>", ... }, // full, not the 400-char preview
71+
"usage": { "n1": { "input": 3571, "output": 8192, "model": "claude-opus-4-8" }, ... },
72+
"turns": { "n1": 2 }, // auto-continuation turns
73+
"trunc": { "n7": true } // hit the safety cap
74+
}
75+
}
76+
```
77+
78+
Cost is derived, never stored (prices drift): `pricing.costOf(model, input, output)`. This same
79+
record is what the cloud archive stores per run, plus `{startedAt, finishedAt, provider, totals,
80+
aborted, failed}` envelope fields.
81+
82+
---
83+
84+
## 4. The Markdown tension (and the resolution)
85+
86+
The instinct "on close, offer to save everything to a Markdown file" is well-meaning but wrong on
87+
two counts:
88+
89+
1. **UX:** a save *prompt* on close is dismissed under time pressure — and then the work is lost
90+
anyway. **Automatic** structured autosave is strictly safer; there's nothing to click.
91+
2. **Business:** a polished, portable Markdown archive of every run *is the sellable artifact.* If
92+
the free tier hands users a complete, portable corpus of their runs, the cloud archive has little
93+
left to sell — they'll keep their own `.md` files in git/Obsidian and never subscribe.
94+
95+
**Resolution — put the free feature on app-internal state, not on the deliverable:**
96+
97+
| | Free local | Paid cloud |
98+
|---|---|---|
99+
| Autosave/restore | `.atompp/.session.json` — **app-internal JSON**, restores *into the live canvas* with meters. Not a browsable corpus. | — |
100+
| Markdown export | **manual, per-run, one-way** — a single chosen deliverable to share. Not a searchable/restorable archive. | — |
101+
| Archive | — | Unlimited, searchable, restore-any-run-anywhere |
102+
| Portability | one machine | every device |
103+
| Insight | the last run's meters | cost analytics across all runs |
104+
105+
The free tier gives you **durability and one-off sharing**; it does **not** give you a portable,
106+
aggregated, cross-device *system of record.* That system is the paid product.
107+
108+
---
109+
110+
## 5. Cloud sync — the paid layer
111+
112+
### 5.1 Reuse the rails you already have
113+
Atom++ Sync already exists: Code-OSS **Settings Sync** pointed at an Atom++-operated store, with the
114+
`atompp` **auth provider** (`configurationSync.store` in `branding/product.overlay.json`; the
115+
`atompp.ai.account` sign-in). Cloud run sync is a **new resource type on the same account + server**,
116+
not a new product. A signed-in Plus user's `.atompp/` run records replicate to the cloud and back.
117+
118+
### 5.2 The features that justify a subscription
119+
120+
| Feature | Why it's worth paying for |
121+
|---|---|
122+
| **Cross-device sync** | Sketches + run results + Activity follow you laptop ↔ desktop; survive a dead machine. The classic sync value. |
123+
| **Unlimited, searchable run archive** | Local Activity caps at the last 100 and one `.session.json`; cloud keeps *every* run forever, searchable by goal/agent/model/cost — a **ledger of what you spent and what you got.** |
124+
| **Cost analytics dashboard** | You already meter tokens/$ per node and ship what-if repricing. Aggregating it — *"$X across N runs this month; the same flows on Haiku would've been $Y"* — is a small step from shipped data with high perceived value. **This is the hook**: a professional watching AI spend will pay for the ledger + the "cheaper-model" delta. |
125+
| **Team sharing** | Share a sketch + its results / a flow-template library; seat management. The collaboration upsell. |
126+
| **Restore-anywhere / backup** | Reinstall on a new Mac, sign in, every run is back. |
127+
128+
### 5.3 Why this is defensible *and* on-strategy
129+
- **BYOK-primary, always.** The user brings their own key; Atom++ **never** marks up or resells
130+
inference (you can't undercut the provider's own subscription — [[atompp-cloud-byok-primary]]).
131+
We sell **software + cloud**: sync, archive, analytics, collaboration. No inference-margin problem.
132+
- **The pain funds the product.** Losing a costly run *creates* demand for durability → sync. The
133+
metering already built makes the analytics/ledger nearly free to build and very compelling to buy.
134+
- **Ethical line:** local durability is free, so nobody pays "not to lose my own work." They pay for
135+
*portability, permanence, insight, and collaboration* — real cloud value.
136+
137+
### 5.4 Suggested tiers
138+
- **Free:** BYOK, all providers, Agent Sketch, **local autosave + restore**, Markdown export, local
139+
Activity (last 100).
140+
- **Atom++ Plus (subscription):** cross-device sync (settings + sketches + runs), unlimited
141+
searchable cloud archive, cost analytics dashboard, restore-anywhere.
142+
- **Team:** shared sketch/template libraries, shared run history, seats/admin.
143+
144+
---
145+
146+
## 6. Roadmap
147+
148+
| Phase | Deliverable | State |
149+
|---|---|---|
150+
| **SK1.2** | Local session autosave + restore; Markdown export | ✅ shipped |
151+
| **RP1** | Local **run history** beyond the latest (keep last N runs per sketch under `.atompp/runs/`, restore any) — still free, still local | next |
152+
| **RP2** | Cloud sync of sketches + run records on the `atompp` account (extend Settings-Sync store); **Plus** gate | paid |
153+
| **RP3** | Cost analytics dashboard (aggregate the metering already captured) — the flagship Plus feature | paid |
154+
| **RP4** | Team sharing: shared libraries + run history + seats | paid |
155+
156+
**Prerequisite for RP2+:** point `configurationSync.store.url` at the managed Atom++ Cloud host (it's
157+
a localhost placeholder today — see `product.overlay.json` `_syncComment`).
158+
159+
---
160+
161+
## 7. Attribution
162+
Builds on the shipped Agent Sketch (SK1), the multi-provider metering (P2/P4), and the Atom++ Sync /
163+
`atompp` auth rails. Persistence is app-internal; the cloud layer is the monetization surface.

‎docs/atompp-agent-sketch-design.md‎

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,47 @@ files). Costs shown are planning estimates from list prices — the provider bil
118118

119119
| Phase | Deliverable |
120120
|---|---|
121-
| **SK2** | **Tool-using nodes**: a node can run the full `agent.js` loop (read/edit/run with Keep-Undo review + per-run checkpoint) so a sketched flow actually edits the workspace; live streamed output in the inspector; run history. |
122-
| **SK3** | **Topologies**: coordinator/hierarchical patterns (a queen node that dispatches + collects, ruflo-style), conditional edges, retry/verify loops; per-flow token budgets with early stop. |
123-
| **SK4** | **Interop**: import/export ruflo swarm configs; publish sketches as shareable templates; sketch → `atompp.ai` chat-agent handoff ("run this flow on the current repo"). |
121+
| **SK1.3** | **Prompt → whole flow** (shipped): type a plain-English description into the (empty) board and the active model designs a complete DAG — `generateFlow()` returns `{goal, nodes, edges}`, normalized to a loadable sketch and auto-laid-out. Empty canvas = *build*; populated canvas = *edit* (the existing ops command). |
122+
| **SK2** | **Tool-using + connector nodes**: a node runs the full `agent.js` loop (read/edit/run with Keep-Undo review) so a sketched flow edits the workspace; **connector nodes actually act** — Telegram/Slack post, email send, webhook call, file write — behind credentials + per-flow permission (see §4). |
123+
| **SK3** | **Triggers & topologies**: a `scheduler`/`webhook-trigger` root fires the flow on a **cron cadence / inbound event** (Managed-Agents-style scheduled deployment); coordinator/hierarchical patterns, conditional edges, retry/verify loops; per-flow token budgets. |
124+
| **SK4** | **Interop**: import/export ruflo swarm configs; publish sketches as shareable templates; sketch → `atompp.ai` chat-agent handoff. |
125+
126+
## 4. Node tiers: text → tools → connectors → triggers
127+
128+
Not every node is the same *kind* of thing. The catalog now spans four execution tiers; SK1 runs them
129+
all as **text-only** (a connector emits the payload it *would* send; a trigger emits the context it
130+
*would* fire with), and later phases make the side-effecting tiers real — each with the safety it needs.
131+
132+
| Tier | Examples | SK1 (today) | Later — what "real" needs |
133+
|---|---|---|---|
134+
| **Text** | coder, researcher, news-collector, copywriter, editor-in-chief | one LLM turn, in/out text | — (this is the whole SK1 model) |
135+
| **Tool / file** | file-writer, and any node run through `agent.js` | outputs the file + contents it *would* write | SK2: writes via the same **Keep/Undo review + per-run checkpoint** the chat agent uses |
136+
| **Connector (actuator)** | telegram-publisher, email-sender, slack-publisher, webhook-caller | outputs the exact message/email/HTTP payload it *would* send | SK2: real send. Needs **(a)** credentials in SecretStorage/keychain (bot token, SMTP creds — never in the sketch file), **(b)** a **per-flow send permission** the user grants once (sending is outward-facing — mirrors the harness "Explicit permission" rule: publishing/messaging requires a clear yes), **(c)** an **allowlist** (which chat/recipient/host), **(d)** a dry-run preview (show the message, click Send) |
137+
| **Trigger** | scheduler (cron), webhook-trigger | the ROOT node; outputs the run context ("collect news since the last run at <time>") | SK3: a **scheduled/triggered run** — cron cadence or inbound webhook fires the downstream DAG unattended. Maps onto the Managed-Agents *scheduled deployment* pattern (cron + per-firing run records) or a local scheduler; ties into the run-persistence archive so every firing is logged |
138+
139+
**Why the tiering is the point:** it keeps SK1 shippable and safe (nothing sends, nothing runs on a
140+
timer — you can design and cost a Telegram-publishing pipeline today and see exactly what it *would*
141+
post), while giving a clear, honest path to real automation where each dangerous capability (send,
142+
write, schedule) is gated by the credential + permission model it deserves. The BYOK rule is unchanged
143+
— connectors use the *user's own* integration credentials; Atom++ never proxies or stores the content.
144+
145+
### Worked example (what the generator produces)
146+
Prompt: *"5 agents collect recent AI & agentic-AI news; a head-of-press-release edits them; a
147+
copywriter verifies and composes one post; publish it to Telegram; run it daily."* →
148+
149+
```
150+
daily-trigger (scheduler)
151+
→ [ai-research · agentic · products · funding · safety] (5 news-collectors, parallel)
152+
→ press-desk (press-editor)
153+
→ copywriter (copywriter)
154+
→ editor-approval (editor-in-chief)
155+
→ telegram-post (telegram-publisher)
156+
```
157+
158+
Today that runs text-only: the collectors produce cited news summaries, the copywriter composes the
159+
post, and `telegram-post` outputs the exact Markdown message it *would* send — metered, costed, and
160+
persisted. SK2 turns `telegram-post` into a real send (bot token + "allow send to @channel"); SK3
161+
makes `daily-trigger` actually fire the flow every morning.
124162

125163
## 3. Attribution & licensing
126164
Agent names/roles derived from ruflo's `.claude/agents/` library (MIT © 2024–2026 ruvnet) — metadata

0 commit comments

Comments
 (0)