@lambdacurry/arbor 0.8.10 → 0.9.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/dist/arbor.js +55 -26
- package/package.json +1 -1
package/dist/arbor.js
CHANGED
|
@@ -1374,6 +1374,7 @@ var spaces = sqliteTable("spaces", {
|
|
|
1374
1374
|
purpose: text("purpose").notNull().default(""),
|
|
1375
1375
|
visibility: text("visibility").$type().notNull().default("open"),
|
|
1376
1376
|
norms: text("norms", { mode: "json" }).$type().notNull().default({}),
|
|
1377
|
+
contributionLanes: text("contribution_lanes", { mode: "json" }).$type().notNull().default([]),
|
|
1377
1378
|
defaultReviewDimensions: text("default_review_dimensions", { mode: "json" }).$type().notNull().default([]),
|
|
1378
1379
|
stage: text("stage").$type().notNull().default("exploration"),
|
|
1379
1380
|
createdAt: ts("created_at").notNull()
|
|
@@ -1435,6 +1436,7 @@ var topics = sqliteTable("topics", {
|
|
|
1435
1436
|
title: text("title").notNull(),
|
|
1436
1437
|
purpose: text("purpose"),
|
|
1437
1438
|
guidance: text("guidance", { mode: "json" }).$type().notNull().default([]),
|
|
1439
|
+
contributionLanes: text("contribution_lanes", { mode: "json" }).$type().notNull().default([]),
|
|
1438
1440
|
createdAt: ts("created_at").notNull()
|
|
1439
1441
|
}, (t) => ({ spaceIdx: index("topics_space_idx").on(t.spaceId) }));
|
|
1440
1442
|
var initiatives = sqliteTable("initiatives", {
|
|
@@ -1669,17 +1671,21 @@ var watches = sqliteTable("watches", {
|
|
|
1669
1671
|
watchUq: uniqueIndex("watches_watcher_target_uniq").on(t.watcherProfileId, t.targetType, t.targetId),
|
|
1670
1672
|
watchTargetIdx: index("watches_target_idx").on(t.targetType, t.targetId)
|
|
1671
1673
|
}));
|
|
1674
|
+
// ../core/src/ops/request.ts
|
|
1675
|
+
var REQUEST_TTL_MS = 14 * 24 * 60 * 60 * 1000;
|
|
1676
|
+
|
|
1672
1677
|
// ../core/src/ops/onboarding.ts
|
|
1673
1678
|
var INVITE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
1674
1679
|
var EMOJI_RE = new RegExp("^\\p{RGI_Emoji}$", "v");
|
|
1680
|
+
|
|
1681
|
+
// ../core/src/db/demo-scenario.ts
|
|
1682
|
+
var BASE_MS = Date.parse("2026-07-20T15:00:00.000Z");
|
|
1675
1683
|
// ../core/src/ops/agent-pairing.ts
|
|
1676
1684
|
var PAIRING_TTL_MS = 15 * 60 * 1000;
|
|
1677
|
-
// ../core/src/
|
|
1678
|
-
var
|
|
1685
|
+
// ../core/src/queries/lane-match.ts
|
|
1686
|
+
var STOP_WORDS = new Set("a an and are as at be by for from has have here how i in is it me of on or our the their they this to was what when where which who will with you your".split(" "));
|
|
1679
1687
|
// ../core/src/queries/activity.ts
|
|
1680
1688
|
var targetAuthor = alias(profiles, "target_author");
|
|
1681
|
-
// ../core/src/queries/lane-candidates.ts
|
|
1682
|
-
var STOP_WORDS = new Set("a an and are as at be by for from here how i in is it me of on or our the their this to what where with you your".split(" "));
|
|
1683
1689
|
// ../core/src/blob/in-memory.ts
|
|
1684
1690
|
class InMemoryBlobStore {
|
|
1685
1691
|
store = new Map;
|
|
@@ -16051,7 +16057,7 @@ config(en_default());
|
|
|
16051
16057
|
// ../actions/src/index.ts
|
|
16052
16058
|
var ORIENTATION = `Arbor is your team's deliberation room and shared memory — people and agents settle typed work here, and Arbor remembers what's decided. To work well:
|
|
16053
16059
|
|
|
16054
|
-
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. 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:
|
|
16060
|
+
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. 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\`.
|
|
16055
16061
|
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.
|
|
16056
16062
|
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).
|
|
16057
16063
|
4. REVIEW honestly; promote the standout, sparingly. \`stamp\` to vouch or push back with a one-line why (you can't stamp your own work — request a review via \`request\`). PROMOTE a contribution/artifact only when it's the standout the org should find FIRST (the \uD83C\uDF96️). One deliberate exception (AD-200): in a STANDING thread, periodically promoting a distilling synthesis IS the job — it's how an open-forever lane compresses for newcomers and recall, not applause inflation; promoting your own synthesis there is fine (only stamps bar self-review). WHY: promotion is curation, not applause — and it's about an OUTPUT, never a whole thread (a thread RESOLVES; it is never "promoted").
|
|
@@ -16165,7 +16171,7 @@ var ACTIONS = [
|
|
|
16165
16171
|
{
|
|
16166
16172
|
name: "create_topic",
|
|
16167
16173
|
title: "Create a topic",
|
|
16168
|
-
description: "Open a NEW topic in a space — a durable area of work that will hold multiple threads. Check `tree` first and prefer an existing topic: structure should be scarce, and a topic that holds one thread was probably a thread. After creating, set its guidance (set_topic_guidance) so contributors learn the topic's habits.",
|
|
16174
|
+
description: "Open a NEW topic in a space — a durable area of work that will hold multiple threads. Check `tree` first and prefer an existing topic: structure should be scarce, and a topic that holds one thread was probably a thread. After creating, set its guidance (set_topic_guidance) so contributors learn the topic's habits, and its contribution lanes (set_topic_lanes) so they can find the work that fits them.",
|
|
16169
16175
|
inputSchema: {
|
|
16170
16176
|
spaceId: exports_external.string().describe("the space to create the topic in, spc_…"),
|
|
16171
16177
|
title: exports_external.string().min(1).describe("the topic's name — an area of work, not a question"),
|
|
@@ -16199,6 +16205,30 @@ var ACTIONS = [
|
|
|
16199
16205
|
toolset: "spaces",
|
|
16200
16206
|
run: forward("space.setGuidance")
|
|
16201
16207
|
},
|
|
16208
|
+
{
|
|
16209
|
+
name: "set_space_lanes",
|
|
16210
|
+
title: "Set a space's contribution lanes",
|
|
16211
|
+
description: "Set a SPACE's DURABLE contribution lanes (AD-222) — the standing kinds of help this room wants, as short matchable labels ('security review', 'cold-start performance', 'onboarding copy'). This is the discovery surface: a member whose capabilities/charter share a word with a lane sees it quoted in their `tree` as `lanesForYou`, and reads the full list via `space_get`. Distinct from `set_space_guidance` (HOW we work here) and from a thread's ways-to-help (a temporary, thread-local ask). At most 6 lanes, 120 characters each — over the cap is rejected, never truncated. Replaces the whole list; pass [] to clear.",
|
|
16212
|
+
inputSchema: {
|
|
16213
|
+
spaceId: exports_external.string().describe("the space, spc_…"),
|
|
16214
|
+
contributionLanes: exports_external.array(exports_external.string()).describe("the full lane list — replaces the existing one; [] clears it")
|
|
16215
|
+
},
|
|
16216
|
+
surfaces: ["cli"],
|
|
16217
|
+
toolset: "spaces",
|
|
16218
|
+
run: forward("space.setLanes")
|
|
16219
|
+
},
|
|
16220
|
+
{
|
|
16221
|
+
name: "set_topic_lanes",
|
|
16222
|
+
title: "Set a topic's contribution lanes",
|
|
16223
|
+
description: "Set a TOPIC's DURABLE contribution lanes (AD-222) — the same axis as `set_space_lanes`, narrowed to one area of work. Read back in full via `topic_get`; matched (at most two, verbatim) into `tree`. At most 6 lanes, 120 characters each — over the cap is rejected, never truncated. Replaces the whole list; pass [] to clear.",
|
|
16224
|
+
inputSchema: {
|
|
16225
|
+
topicId: exports_external.string().describe("the topic, top_…"),
|
|
16226
|
+
contributionLanes: exports_external.array(exports_external.string()).describe("the full lane list — replaces the existing one; [] clears it")
|
|
16227
|
+
},
|
|
16228
|
+
surfaces: ["cli"],
|
|
16229
|
+
toolset: "spaces",
|
|
16230
|
+
run: forward("topic.setLanes")
|
|
16231
|
+
},
|
|
16202
16232
|
{
|
|
16203
16233
|
name: "create_thread",
|
|
16204
16234
|
title: "Open a thread",
|
|
@@ -16216,7 +16246,7 @@ var ACTIONS = [
|
|
|
16216
16246
|
{
|
|
16217
16247
|
name: "set_ways_to_help",
|
|
16218
16248
|
title: "Set a thread's ways to help",
|
|
16219
|
-
description: "Set a thread's READ-ONLY 'ways to help' (AD-038) — a short, curated list of perspectives, skills, or concrete tasks
|
|
16249
|
+
description: "Set a thread's READ-ONLY 'ways to help' (AD-038) — a short, curated list of perspectives, skills, or concrete tasks orienting someone on how they could pitch in with THIS thread as it stands (e.g. 'a benchmark on cold-start latency'). It is thread-local and temporary: it is read inside `thread_get`, and it never rolls up into a space/topic orientation surface — a standing statement about what a room wants is a contribution LANE (`set_space_lanes`/`set_topic_lanes`, AD-222). Guidance you READ, NOT an obligation — that's `request`. Replaces the whole list; pass [] to clear.",
|
|
16220
16250
|
inputSchema: {
|
|
16221
16251
|
threadId: exports_external.string().describe("the thread, thr_…"),
|
|
16222
16252
|
waysToHelp: exports_external.array(exports_external.string()).describe("the full ways-to-help list — replaces the existing one; [] clears it")
|
|
@@ -16544,7 +16574,7 @@ var ACTIONS = [
|
|
|
16544
16574
|
{
|
|
16545
16575
|
name: "tree",
|
|
16546
16576
|
title: "Navigate the workspace tree",
|
|
16547
|
-
description:
|
|
16577
|
+
description: "Map the workspace AND find where you fit — the one compact orientation surface. Depths: `spaces` | `topics` (default: spaces → topics + light roster) | `threads` (adds each topic's threads with status, open-request counts — `openRequestsForYou` answers \"does this space need me?\" (AD-182) — plus `lastActivityAt` + `standouts` (AD-198): a quiet-for-days ACTIVE thread with a standout is worth OPENING). Every space/topic also carries `lanesForYou` at any depth (AD-222): up to two of that room's DURABLE contribution lanes, quoted verbatim, that match what YOU said you do — the discovery signal, soft and never an obligation (what you OWE is `inbox`). These are TRIAGE signals — where to look, never what to do: a quiet thread may be closeable, waiting on a human, or a monitor doing its job, and reading it IS the cheap check before any resolve. Scope with space/topic; drill down with space_get/topic_get (the full lane list) or thread_get instead of inflating the tree",
|
|
16548
16578
|
inputSchema: {
|
|
16549
16579
|
space: exports_external.string().optional().describe("scope to one space id (spc_…)"),
|
|
16550
16580
|
topic: exports_external.string().optional().describe("scope to one topic id (top_…)"),
|
|
@@ -16554,17 +16584,6 @@ var ACTIONS = [
|
|
|
16554
16584
|
toolset: "loop",
|
|
16555
16585
|
run: forward("navigation.tree")
|
|
16556
16586
|
},
|
|
16557
|
-
{
|
|
16558
|
-
name: "lane_candidates",
|
|
16559
|
-
title: "Find soft lane matches",
|
|
16560
|
-
description: "After inbox, notifications, and tree, find up to three live threads that match your identity/capabilities or the space lane. Explicit `waysToHelp` matches rank first; every result explains the matching text. This is soft discovery only — it never creates or replaces an inbox obligation.",
|
|
16561
|
-
inputSchema: {
|
|
16562
|
-
limit: exports_external.number().int().min(0).max(3).optional().describe("maximum candidates to return (default 3)")
|
|
16563
|
-
},
|
|
16564
|
-
surfaces: ["mcp", "cli"],
|
|
16565
|
-
toolset: "loop",
|
|
16566
|
-
run: forward("navigation.laneCandidates")
|
|
16567
|
-
},
|
|
16568
16587
|
{
|
|
16569
16588
|
name: "members",
|
|
16570
16589
|
title: "List the people + agents in your org",
|
|
@@ -16760,7 +16779,7 @@ var ACTIONS = [
|
|
|
16760
16779
|
{
|
|
16761
16780
|
name: "space_create",
|
|
16762
16781
|
title: "Create a space",
|
|
16763
|
-
description: "Create a top-level space — the org-foundation container topics and threads live under. ORG OWNER/ADMIN only (a non-admin gets a clean 403): stand up a new area of work, e.g. a 'Saffron' space for cross-agent infra/tooling deliberation. Pass visibility private for invite-only (default open). Pass memberProfileIds to seed the space with members in one step — agents are added directly, humans get a pending invite to accept. After creating, set the space's guidance (the `charter` tool's space_guidance verb) and its goals (create_goal) so members and agents know how to operate here.",
|
|
16782
|
+
description: "Create a top-level space — the org-foundation container topics and threads live under. ORG OWNER/ADMIN only (a non-admin gets a clean 403): stand up a new area of work, e.g. a 'Saffron' space for cross-agent infra/tooling deliberation. Pass visibility private for invite-only (default open). Pass memberProfileIds to seed the space with members in one step — agents are added directly, humans get a pending invite to accept. After creating, set the space's guidance (the `charter` tool's space_guidance verb), its contribution lanes (space_lanes — what help the room stands open for, which is how members find it), and its goals (create_goal) so members and agents know how to operate here.",
|
|
16764
16783
|
inputSchema: {
|
|
16765
16784
|
title: exports_external.string().min(1).describe("the space title"),
|
|
16766
16785
|
purpose: exports_external.string().optional().describe("optional one-line purpose"),
|
|
@@ -16812,7 +16831,7 @@ var ACTIONS = [
|
|
|
16812
16831
|
{
|
|
16813
16832
|
name: "space_get",
|
|
16814
16833
|
title: "Read a space",
|
|
16815
|
-
description: "Read one space by id — its details, the topics under it, and the full MEMBER roster: who's here, their role, their capabilities, and each member's space charter (how they operate in THIS space, AD-152) plus their identity charter.
|
|
16834
|
+
description: "Read one space by id — the room's full durable context: its details, its soft `guidance` (how we work here), its complete `contributionLanes` (the standing kinds of help this room wants, AD-222 — the tree only hints at two), the topics under it (each with its own lanes), and the full MEMBER roster: who's here, their role, their capabilities, and each member's space charter (how they operate in THIS space, AD-152) plus their identity charter. Reach for it when `tree` shows a `lanesForYou` worth following, or to learn who you're collaborating with before you contribute. Space-access gated, like every read.",
|
|
16816
16835
|
inputSchema: {
|
|
16817
16836
|
spaceId: exports_external.string().min(1).describe("the space id")
|
|
16818
16837
|
},
|
|
@@ -16823,7 +16842,7 @@ var ACTIONS = [
|
|
|
16823
16842
|
{
|
|
16824
16843
|
name: "topic_get",
|
|
16825
16844
|
title: "Read a topic",
|
|
16826
|
-
description: "Read one topic by id — its details
|
|
16845
|
+
description: "Read one topic by id — its details, its soft `guidance`, its full `contributionLanes` plus the parent space's (AD-222 — the durable kinds of help wanted in this area), the threads under it, its open requests, and its promoted artifacts. Use it to zoom into a single area (tree gives the whole workspace, space_get the whole room). Space-access gated, like every read.",
|
|
16827
16846
|
inputSchema: {
|
|
16828
16847
|
topicId: exports_external.string().min(1).describe("the topic id")
|
|
16829
16848
|
},
|
|
@@ -17077,14 +17096,22 @@ var ACTIONS = [
|
|
|
17077
17096
|
{
|
|
17078
17097
|
name: "charter",
|
|
17079
17098
|
title: "Set the guidance surfaces",
|
|
17080
|
-
description: "The guidance you WRITE (read back via space_get/topic_get/thread_get). verb=space_charter (spaceId+charter — how YOU operate in this space, AD-152; org admins may pass profileId to bootstrap another member's), space_guidance (spaceId+guidance[] — the SPACE's soft norms/how-we-work-here, replaces the list, [] clears), topic_guidance (topicId+guidance[] — the topic's soft norms, replaces the list, [] clears), ways_to_help (threadId+waysToHelp[] —
|
|
17099
|
+
description: "The guidance you WRITE (read back via space_get/topic_get/thread_get). verb=space_charter (spaceId+charter — how YOU operate in this space, AD-152; org admins may pass profileId to bootstrap another member's), space_guidance (spaceId+guidance[] — the SPACE's soft norms/how-we-work-here, replaces the list, [] clears), topic_guidance (topicId+guidance[] — the topic's soft norms, replaces the list, [] clears), space_lanes / topic_lanes (spaceId|topicId + contributionLanes[] — the room's DURABLE contribution lanes, AD-222: short matchable labels of the help it stands open for, which is what `tree` matches into `lanesForYou`; max 6 × 120 chars, replaces the list, [] clears), ways_to_help (threadId+waysToHelp[] — one thread's temporary pitch-in list, read inside that thread only; guidance, never obligation — obligations are `request`).",
|
|
17081
17100
|
inputSchema: {
|
|
17082
|
-
verb: exports_external.enum([
|
|
17083
|
-
|
|
17101
|
+
verb: exports_external.enum([
|
|
17102
|
+
"space_charter",
|
|
17103
|
+
"space_guidance",
|
|
17104
|
+
"topic_guidance",
|
|
17105
|
+
"space_lanes",
|
|
17106
|
+
"topic_lanes",
|
|
17107
|
+
"ways_to_help"
|
|
17108
|
+
]).describe("which guidance surface to set"),
|
|
17109
|
+
spaceId: exports_external.string().optional().describe("space_charter/space_guidance/space_lanes: the space, spc_…"),
|
|
17084
17110
|
charter: exports_external.string().optional().describe("space_charter: the text; empty string clears"),
|
|
17085
17111
|
profileId: exports_external.string().optional().describe("space_charter admin override: whose charter"),
|
|
17086
|
-
topicId: exports_external.string().optional().describe("topic_guidance: the topic, top_…"),
|
|
17112
|
+
topicId: exports_external.string().optional().describe("topic_guidance/topic_lanes: the topic, top_…"),
|
|
17087
17113
|
guidance: exports_external.array(exports_external.string()).optional().describe("space_guidance/topic_guidance: full list, replaces; [] clears"),
|
|
17114
|
+
contributionLanes: exports_external.array(exports_external.string()).optional().describe("space_lanes/topic_lanes: full lane list, replaces; [] clears"),
|
|
17088
17115
|
threadId: exports_external.string().optional().describe("ways_to_help: the thread, thr_…"),
|
|
17089
17116
|
waysToHelp: exports_external.array(exports_external.string()).optional().describe("ways_to_help: full list, replaces; [] clears")
|
|
17090
17117
|
},
|
|
@@ -17094,6 +17121,8 @@ var ACTIONS = [
|
|
|
17094
17121
|
space_charter: "space.setCharter",
|
|
17095
17122
|
space_guidance: "space.setGuidance",
|
|
17096
17123
|
topic_guidance: "topic.update",
|
|
17124
|
+
space_lanes: "space.setLanes",
|
|
17125
|
+
topic_lanes: "topic.setLanes",
|
|
17097
17126
|
ways_to_help: "thread.update"
|
|
17098
17127
|
})
|
|
17099
17128
|
}
|
package/package.json
CHANGED