@lambdacurry/arbor 0.20.33 → 0.21.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.
Files changed (2) hide show
  1. package/dist/arbor.js +31 -69
  2. package/package.json +1 -1
package/dist/arbor.js CHANGED
@@ -17808,17 +17808,6 @@ var MCP_OUTPUT_SCHEMAS = {
17808
17808
  connected: exports_external.boolean(),
17809
17809
  inheritedBySiblingThreads: exports_external.boolean()
17810
17810
  }),
17811
- publish_topic_computer: exports_external.looseObject({
17812
- published: exports_external.boolean(),
17813
- snapshot
17814
- }),
17815
- checkpoint_computer: exports_external.looseObject({
17816
- ok: exports_external.boolean(),
17817
- idempotent: exports_external.boolean().optional(),
17818
- snapshot: snapshot.optional(),
17819
- reason: exports_external.string().optional(),
17820
- currentSnapshotId: nullableString.optional()
17821
- }),
17822
17811
  transition_thread: exports_external.looseObject({ status: exports_external.string() }),
17823
17812
  request: exports_external.looseObject({
17824
17813
  requestId: id,
@@ -18597,8 +18586,6 @@ var MCP_TOOL_ANNOTATIONS = {
18597
18586
  attach_computer: additive,
18598
18587
  get_computer: readOnly,
18599
18588
  computer_inventory: readOnly,
18600
- publish_topic_computer: additive,
18601
- checkpoint_computer: additive,
18602
18589
  transition_thread: additive,
18603
18590
  request: additive,
18604
18591
  respond: additive,
@@ -18696,6 +18683,8 @@ var ORIENTATION = `Arbor is your team's deliberation room and shared memory —
18696
18683
 
18697
18684
  Meaningful friction with Arbor itself can be privately contributed through \`contribute_arbor_feedback\`; the raw body is never posted into the current Thread or the shared Arbor Feedback forum. Browse the curated shared forum with \`feedback_tree\` → \`feedback_recall\` → \`feedback_thread_get\`.
18698
18685
 
18686
+ Arbor's MCP is the collaboration and durable-knowledge surface. Configure, authorize, open, run, verify, package, deploy, and operate software through the separate Arbor Computer MCP at \`/computer/mcp\`; first-class Organization/Profile Secret administration stays here in Arbor, while App runtime configuration on Arbor Computer references those Secret ids without exposing material.
18687
+
18699
18688
  1. RECALL FIRST — but Arbor is MEMORY, NOT TRUTH. Run \`recall\` before re-deriving or restating anything — it may already be settled; cite prior work ([label](#con_…)) and build on it. Phrase the query in PROBLEM-LANGUAGE (a natural-language question — "how do agents handle X"), not extracted keywords; it ranks better. Empty recall is itself worth noting. In a large Space, don't search the whole org by habit: use \`tree\` to choose the room, then scope \`recall\` with \`space\`/\`topic\`/\`thread\` before deeper reads. On that map, \`activeThreadCount\` is the current working set (active/stuck/needs-review/standing), while \`status\` is the Topic attention rollup: \`stuck\` means any stuck Thread; \`attention\` means needs-review or an open request; \`healthy\` means neither. A contribution records what was true when it was WRITTEN, so before you assert the CURRENT state of anything outside Arbor — a PR, a build, a deploy, a config — check the live source; another contribution is not evidence of the present, and neither is a local copy of something whose home is elsewhere. And when you DO check, post the RECEIPT with the claim (AD-209): attach the actual output/screenshot (an attached file becomes a durable artifact carrying who-captured-it and when, citable as #art_… forever) or name exactly what you checked and when ("CI run #841, green, checked just now") — a "verified" with no receipt is a claim the next reader must take on faith or re-derive. When a receipted claim has AGED and matters again, don't re-trust it and don't silently re-argue it: \`request\` a re-check ("re-run this check"), and whoever runs it answers through the request with fresh evidence. WHY: a room where everyone re-derives is just a chat log — but a room that mistakes its own memory for the world confidently reports blockers that no longer exist, and this week's failures were exactly that: stale claims re-asserted as current because nothing distinguished a receipted observation from confident prose. And orient to the ROOM the way you orient to the record: \`tree\` is the map AND the way in — it carries each room's \`lanesForYou\`, the durable contribution lanes that match what you said you do; follow one into \`space_get\`/\`topic_get\`, where the room's purpose, guidance, goals, and full lane list live. A lane is an invitation, never an obligation: what you OWE is only ever in \`inbox\`.
18700
18689
  2. CONTRIBUTE typed points — but ADD ONLY WHAT'S ADDITIVE (AD-205). Ask what the most additive move is, not whether to say something: if your reaction to a point already on the record fits in one line — agree OR disagree — STAMP it (vouch, or push back with a one-line why), don't restate it; if you'd only echo consensus, reviewing IS the contribution and staying out is fine. When you DO contribute, it's ONE point, with the type that names your move (proposal / critique / question / evidence / risk / correction / assertion / decision). Markdown welcome; put references IN your prose (a URL or [label](#con_…) becomes a navigable reference). Prose refs are CITATIONS — they never move your contribution in the thread, so cite freely; to REPLY under a specific contribution, pass links: [{rel: 'inReplyTo', targetId}] (AD-196). WHY: a thread where every agent restates the consensus is noise — the record is strongest when each point appears ONCE and gets vouched (or contested) with a stamp, not re-said; and one typed point is reviewable on its own, so a synthesis citing five points should read as the most top-level thing in the thread, not as a reply to the first one it mentions.
18701
18690
  3. ANSWER through requests. When \`inbox\` or a thread shows an open request you can meet, answer THROUGH it — \`respond\` to it, or \`stamp\` the contribution a review request is about — so it completes and the requester is notified. WHY: a plain reply that merely happens to answer leaves their request hanging (the most common failure).
@@ -18754,23 +18743,23 @@ var ACTION_DEFINITIONS = [
18754
18743
  {
18755
18744
  name: "github_repositories",
18756
18745
  title: "List installed GitHub repositories",
18757
- description: "READ ONLY: List repositories covered by this organization's verified Arbor Computer GitHub App that any collaborator may inspect; returns repository ids and metadata, never credentials, for use with github_connect_repository. Listing is not authority: connecting still requires permission over the chosen scope.",
18746
+ description: "READ ONLY: List repositories covered by this organization's verified Arbor Computer GitHub App, returning ids and metadata but never credentials. Use github_connect_repository to authorize one at an Arbor scope; listing alone grants no Computer access.",
18758
18747
  inputSchema: { ...PAGINATION_INPUT },
18759
- surfaces: ["mcp", "cli"],
18748
+ surfaces: ["computer-mcp", "cli"],
18760
18749
  toolset: "projects",
18761
18750
  run: forward("github.repositories")
18762
18751
  },
18763
18752
  {
18764
18753
  name: "github_connect_repository",
18765
18754
  title: "Connect a GitHub repository",
18766
- description: "Connect/disconnect a GitHub repository at organization, Space, Topic, or Thread scope; it authorizes descendant Threads, while recipes only name it and grant no Git credential; inspect get_computer.repositoryAuthorization for the granting scope. You may connect at ANY SCOPE YOU ALREADY MANAGE: Thread/Topic use config permission, Space needs Space admin, the organization stays owner/admin; Disconnecting takes the same permission, and GitHub installation coverage remains a separate hard gate.",
18755
+ description: "Connect or disconnect a listed GitHub repository at organization, Space, Topic, or Thread scope so matching descendant Computers may materialize it. The caller must manage that scope, GitHub installation coverage remains a separate gate, and get_computer shows the effective grant.",
18767
18756
  inputSchema: {
18768
18757
  repositoryId: exports_external.string().describe("installed repository id from github_repositories, ghr_…"),
18769
18758
  scope: exports_external.enum(["organization", "space", "topic", "thread"]).describe("the Arbor scope that may use this repository's context; topic is the durable choice for a project every Thread under it develops"),
18770
18759
  scopeId: exports_external.string().describe("id matching the selected scope"),
18771
18760
  connected: exports_external.boolean().describe("true to connect; false to disconnect recoverably")
18772
18761
  },
18773
- surfaces: ["mcp", "cli"],
18762
+ surfaces: ["computer-mcp", "cli"],
18774
18763
  toolset: "projects",
18775
18764
  run: forward("github.set_repository_connection")
18776
18765
  },
@@ -19151,7 +19140,7 @@ var ACTION_DEFINITIONS = [
19151
19140
  setupScript: exports_external.string().nullable().optional().describe("optional strict Bash setup run after connected repositories materialize, or null to clear"),
19152
19141
  repositories: exports_external.array(exports_external.string()).max(MAX_COMPUTER_REPOSITORIES).nullable().optional().describe("connected GitHub repositories to materialize into a fresh reusable base and allow for later Git calls; [] clears and null inherits")
19153
19142
  },
19154
- surfaces: ["mcp", "cli"],
19143
+ surfaces: ["computer-mcp", "cli"],
19155
19144
  toolset: "structure",
19156
19145
  run: forward("computer_config.set_organization")
19157
19146
  },
@@ -19166,7 +19155,7 @@ var ACTION_DEFINITIONS = [
19166
19155
  setupScript: exports_external.string().nullable().optional().describe("optional strict Bash setup run after connected repositories materialize, or null to clear"),
19167
19156
  repositories: exports_external.array(exports_external.string()).max(MAX_COMPUTER_REPOSITORIES).nullable().optional().describe("connected GitHub repositories to materialize into a fresh reusable base and allow for later Git calls; [] clears and null inherits")
19168
19157
  },
19169
- surfaces: ["mcp", "cli"],
19158
+ surfaces: ["computer-mcp", "cli"],
19170
19159
  toolset: "structure",
19171
19160
  run: forward("computer_config.set_space")
19172
19161
  },
@@ -19182,7 +19171,7 @@ var ACTION_DEFINITIONS = [
19182
19171
  repositories: exports_external.array(exports_external.string()).max(MAX_COMPUTER_REPOSITORIES).nullable().optional().describe("connected GitHub repositories to materialize into a fresh reusable base and allow for later Git calls; [] clears and null inherits"),
19183
19172
  ...LIVE_PREVIEW_CONFIG_INPUT
19184
19173
  },
19185
- surfaces: ["mcp", "cli"],
19174
+ surfaces: ["computer-mcp", "cli"],
19186
19175
  toolset: "structure",
19187
19176
  run: forward("computer_config.set_topic")
19188
19177
  },
@@ -19198,18 +19187,18 @@ var ACTION_DEFINITIONS = [
19198
19187
  repositories: exports_external.array(exports_external.string()).max(MAX_COMPUTER_REPOSITORIES).nullable().optional().describe("connected GitHub repositories to materialize into a fresh reusable base and allow for later Git calls; [] clears and null inherits"),
19199
19188
  ...LIVE_PREVIEW_CONFIG_INPUT
19200
19189
  },
19201
- surfaces: ["mcp", "cli"],
19190
+ surfaces: ["computer-mcp", "cli"],
19202
19191
  toolset: "structure",
19203
19192
  run: forward("computer_config.set_thread")
19204
19193
  },
19205
19194
  {
19206
19195
  name: "attach_computer",
19207
19196
  title: "Attach a Thread computer",
19208
- description: "Lazily attach the one stable computer identity to a Thread and mint an immutable, server-attributed session receipt. This protocol action allocates no runtime and returns no bearer secret; use the separate Arbor Computer MCP or `arbor computer open` for execution.",
19197
+ description: "Create or reuse a Thread's stable Computer identity and mint an immutable collaborator receipt without starting provider runtime. Normally computer_open performs this attachment as part of opening; use this tool only when durable protocol identity is needed separately.",
19209
19198
  inputSchema: {
19210
19199
  threadId: exports_external.string().describe("the Thread whose computer you are attaching, thr_…")
19211
19200
  },
19212
- surfaces: ["mcp", "cli"],
19201
+ surfaces: ["computer-mcp", "cli"],
19213
19202
  toolset: "loop",
19214
19203
  run: forward("computer.attach")
19215
19204
  },
@@ -19235,7 +19224,7 @@ var ACTION_DEFINITIONS = [
19235
19224
  idempotencyKey: exports_external.string().min(1).max(200).describe("stable key for this ONE replacement request; reuse it unchanged for retries"),
19236
19225
  reason: exports_external.string().min(1).max(500).describe("concise auditable reason for replacing the active generation")
19237
19226
  },
19238
- surfaces: ["mcp", "computer-mcp", "computer-cli"],
19227
+ surfaces: ["computer-mcp", "computer-cli"],
19239
19228
  toolset: "loop",
19240
19229
  run: forward("computer_runtime.reprovision")
19241
19230
  },
@@ -19554,50 +19543,23 @@ var ACTION_DEFINITIONS = [
19554
19543
  threadId: exports_external.string().describe("the Thread, thr_…"),
19555
19544
  lineageLimit: exports_external.number().int().min(1).max(100).optional().describe("recent receipts/lineage rows (default 20)")
19556
19545
  },
19557
- surfaces: ["mcp", "cli"],
19546
+ surfaces: ["computer-mcp", "cli"],
19558
19547
  toolset: "loop",
19559
19548
  run: forward("computer.get")
19560
19549
  },
19561
19550
  {
19562
19551
  name: "computer_inventory",
19563
19552
  title: "Inventory organization Computers",
19564
- description: "READ ONLY: Inventory materialized Thread Computers in your organization, optionally scoped to one Topic. Reports active generation, recipe compatibility, counts for generations/sessions/snapshots/Runs, and factual flags for stale recipes, superseded generations, active Runs and failed reprovisions. Organization owner/admin only. This is an operational read model, not a deletion recommendation.",
19553
+ description: "READ ONLY: Inventory materialized Thread Computers in your organization, optionally scoped to a Topic, with active generation, compatibility, lifecycle counts, and factual anomaly flags. Organization owner/admin only; this is evidence, not a deletion recommendation.",
19565
19554
  inputSchema: {
19566
19555
  topicId: exports_external.string().optional().describe("optional Topic to scope the inventory"),
19567
19556
  limit: exports_external.number().int().min(1).max(50).optional().describe("rows to return (default 25)"),
19568
19557
  cursor: exports_external.string().optional().describe("active Computer id returned as nextCursor by the previous page")
19569
19558
  },
19570
- surfaces: ["mcp", "cli"],
19559
+ surfaces: ["computer-mcp", "cli"],
19571
19560
  toolset: "admin",
19572
19561
  run: forward("computer.inventory")
19573
19562
  },
19574
- {
19575
- name: "publish_topic_computer",
19576
- title: "Publish a Topic computer base",
19577
- description: "After the first attached collaborator finishes the Topic setup recipe and Currybox checkpoints `/workspace`, publish that opaque restore handle as the reusable Topic base. Arbor verifies it server-to-server and publication is first-writer-wins; a losing concurrent backup is an orphan for Currybox GC.",
19578
- inputSchema: {
19579
- sessionId: exports_external.string().describe("the Arbor computer session that materialized the base, cms_…"),
19580
- providerRef: exports_external.string().describe("the opaque restore handle returned by `currybox checkpoint`")
19581
- },
19582
- surfaces: ["mcp", "cli"],
19583
- toolset: "loop",
19584
- run: forward("computer.publish_topic_base")
19585
- },
19586
- {
19587
- name: "checkpoint_computer",
19588
- title: "Checkpoint a Thread computer",
19589
- description: "After a complete unit of work, checkpoint `/workspace` through Currybox, then publish its opaque handle here to append immutable Thread lineage and advance the current pointer atomically. Pass the current snapshot id you read (or null before the first Thread checkpoint); stale writers get a structured conflict instead of overwriting work.",
19590
- inputSchema: {
19591
- computerId: exports_external.string().describe("the stable Thread computer, cmp_…"),
19592
- sessionId: exports_external.string().optional().describe("the producing agent session, cms_…; Currybox service sweeps omit it"),
19593
- providerRef: exports_external.string().describe("the opaque restore handle returned by `currybox checkpoint`"),
19594
- expectedCurrentSnapshotId: exports_external.string().nullable().describe("the current Thread snapshot id you read, or null before its first checkpoint"),
19595
- parentSnapshotId: exports_external.string().optional().describe("first checkpoint only: the Topic base parent when the session cannot supply it")
19596
- },
19597
- surfaces: ["mcp", "cli"],
19598
- toolset: "loop",
19599
- run: forward("computer.checkpoint")
19600
- },
19601
19563
  {
19602
19564
  name: "set_ways_to_help",
19603
19565
  title: "Set a thread's ways to help",
@@ -20592,7 +20554,7 @@ var ACTION_DEFINITIONS = [
20592
20554
  bindingId: exports_external.string().optional().describe("unbind: binding id, sbd_…")
20593
20555
  },
20594
20556
  surfaces: ["mcp"],
20595
- toolset: "apps",
20557
+ toolset: "secrets",
20596
20558
  run: dispatch({
20597
20559
  list: "secret.list",
20598
20560
  get: "secret.get",
@@ -20746,7 +20708,7 @@ var ACTION_DEFINITIONS = [
20746
20708
  inputSchema: {
20747
20709
  includeArchived: exports_external.boolean().optional().describe("include archived Apps you are authorized to inspect")
20748
20710
  },
20749
- surfaces: ["mcp"],
20711
+ surfaces: ["computer-mcp"],
20750
20712
  toolset: "apps",
20751
20713
  run: forward("app.list")
20752
20714
  },
@@ -20755,7 +20717,7 @@ var ACTION_DEFINITIONS = [
20755
20717
  title: "Read an App",
20756
20718
  description: "READ ONLY: Inspect one App's stable URL, active deployment, pending control intent, deployment history, provider health, deployment-aware redacted configuration readiness for the active release, and durable state generation. It cannot modify App state, deployment state, access, or durable SQLite; use its activeDeploymentId as app_activate's expectedActiveDeploymentId.",
20757
20719
  inputSchema: { appId: exports_external.string().describe("the App, app_…") },
20758
- surfaces: ["mcp", "cli"],
20720
+ surfaces: ["computer-mcp", "cli"],
20759
20721
  toolset: "apps",
20760
20722
  run: forward("app.get")
20761
20723
  },
@@ -20772,7 +20734,7 @@ var ACTION_DEFINITIONS = [
20772
20734
  discovery: exports_external.enum(["unlisted", "listed"]).nullable().optional().describe("public Apps only; default unlisted"),
20773
20735
  stateMode: exports_external.enum(["none", "durable"]).describe("durable allocates Space-only isolated facet SQLite; deployment never resets it")
20774
20736
  },
20775
- surfaces: ["mcp", "cli"],
20737
+ surfaces: ["computer-mcp", "cli"],
20776
20738
  toolset: "apps",
20777
20739
  run: forward("app.create")
20778
20740
  },
@@ -20788,7 +20750,7 @@ var ACTION_DEFINITIONS = [
20788
20750
  ])).describe("complete desired runtime config object keyed by environment variable name"),
20789
20751
  dryRun: exports_external.boolean().optional().describe("validate and plan without mutating")
20790
20752
  },
20791
- surfaces: ["mcp", "cli"],
20753
+ surfaces: ["computer-mcp", "cli"],
20792
20754
  toolset: "apps",
20793
20755
  run: forward("app.config_apply")
20794
20756
  },
@@ -20801,7 +20763,7 @@ var ACTION_DEFINITIONS = [
20801
20763
  bundleId: exports_external.string().describe("verified immutable AppBundle, bnd_…"),
20802
20764
  idempotencyKey: exports_external.string().min(1).max(200).describe("stable key for this one logical deployment attempt")
20803
20765
  },
20804
- surfaces: ["mcp", "cli"],
20766
+ surfaces: ["computer-mcp", "cli"],
20805
20767
  toolset: "apps",
20806
20768
  run: forward("app.deploy")
20807
20769
  },
@@ -20825,7 +20787,7 @@ var ACTION_DEFINITIONS = [
20825
20787
  appId: exports_external.string().describe("owning App, app_…"),
20826
20788
  deploymentId: exports_external.string().describe("deployment, dep_…")
20827
20789
  },
20828
- surfaces: ["mcp"],
20790
+ surfaces: ["computer-mcp"],
20829
20791
  toolset: "apps",
20830
20792
  run: forward("app.deployment_get")
20831
20793
  },
@@ -20838,7 +20800,7 @@ var ACTION_DEFINITIONS = [
20838
20800
  path: exports_external.string().min(1).max(2048).describe("relative App path beginning with /; may include a query string"),
20839
20801
  method: exports_external.enum(["GET", "HEAD"]).optional().describe("safe read method; default GET")
20840
20802
  },
20841
- surfaces: ["mcp", "cli"],
20803
+ surfaces: ["computer-mcp", "cli"],
20842
20804
  toolset: "apps",
20843
20805
  run: forward("app.fetch")
20844
20806
  },
@@ -20854,7 +20816,7 @@ var ACTION_DEFINITIONS = [
20854
20816
  body: exports_external.string().optional().describe("UTF-8 request body; mutually exclusive with json"),
20855
20817
  contentType: exports_external.string().max(160).optional().describe("body media type; allowed only with body, default text/plain; charset=utf-8")
20856
20818
  },
20857
- surfaces: ["mcp", "cli"],
20819
+ surfaces: ["computer-mcp", "cli"],
20858
20820
  toolset: "apps",
20859
20821
  run: forward("app.request")
20860
20822
  },
@@ -20867,7 +20829,7 @@ var ACTION_DEFINITIONS = [
20867
20829
  deploymentId: exports_external.string().describe("prepared candidate, dep_…"),
20868
20830
  expectedActiveDeploymentId: exports_external.string().nullable().describe("active deployment from app_get, or null before first activation")
20869
20831
  },
20870
- surfaces: ["mcp", "cli"],
20832
+ surfaces: ["computer-mcp", "cli"],
20871
20833
  toolset: "apps",
20872
20834
  run: forward("app.activate")
20873
20835
  },
@@ -20880,7 +20842,7 @@ var ACTION_DEFINITIONS = [
20880
20842
  deploymentId: exports_external.string().describe("superseded deployment to restore, dep_…"),
20881
20843
  expectedActiveDeploymentId: exports_external.string().describe("current active deployment from app_get")
20882
20844
  },
20883
- surfaces: ["mcp", "cli"],
20845
+ surfaces: ["computer-mcp", "cli"],
20884
20846
  toolset: "apps",
20885
20847
  run: forward("app.rollback")
20886
20848
  },
@@ -20906,7 +20868,7 @@ var ACTION_DEFINITIONS = [
20906
20868
  access: exports_external.enum(["space", "public"]).describe("new gateway access"),
20907
20869
  discovery: exports_external.enum(["unlisted", "listed"]).nullable().optional().describe("required concept only for public Apps")
20908
20870
  },
20909
- surfaces: ["mcp", "cli"],
20871
+ surfaces: ["computer-mcp", "cli"],
20910
20872
  toolset: "apps",
20911
20873
  run: forward("app.set_access")
20912
20874
  },
@@ -20919,7 +20881,7 @@ var ACTION_DEFINITIONS = [
20919
20881
  expectedGeneration: exports_external.number().int().min(0).describe("state generation from app_get"),
20920
20882
  idempotencyKey: exports_external.string().min(1).max(200).describe("stable key for this one deliberate reset")
20921
20883
  },
20922
- surfaces: ["mcp", "cli"],
20884
+ surfaces: ["computer-mcp", "cli"],
20923
20885
  toolset: "apps",
20924
20886
  run: forward("app.reset_state")
20925
20887
  },
@@ -20933,7 +20895,7 @@ var ACTION_DEFINITIONS = [
20933
20895
  expectedGeneration: exports_external.number().int().min(0).describe("state generation from app_get"),
20934
20896
  idempotencyKey: exports_external.string().min(1).max(200).describe("stable key for this one deliberate recovery")
20935
20897
  },
20936
- surfaces: ["mcp", "cli"],
20898
+ surfaces: ["computer-mcp", "cli"],
20937
20899
  toolset: "apps",
20938
20900
  run: forward("app.restore_state")
20939
20901
  },
@@ -20942,7 +20904,7 @@ var ACTION_DEFINITIONS = [
20942
20904
  title: "Archive an App",
20943
20905
  description: "Remove an App from active serving while retaining its stable identity, deployment timeline, receipts, durable state, and release history for audit and recovery. Archive is a lifecycle-only transition.",
20944
20906
  inputSchema: { appId: exports_external.string().describe("target App, app_…") },
20945
- surfaces: ["mcp", "cli"],
20907
+ surfaces: ["computer-mcp", "cli"],
20946
20908
  toolset: "apps",
20947
20909
  run: forward("app.archive")
20948
20910
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lambdacurry/arbor",
3
- "version": "0.20.33",
3
+ "version": "0.21.0",
4
4
  "description": "The Arbor CLI — a shared workspace for people and agents. The human + headless-agent write path over Arbor's guarded operation surface.",
5
5
  "keywords": [
6
6
  "agents",