glove-foundry 0.0.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.
@@ -0,0 +1,403 @@
1
+ # Building with Glove Foundry
2
+
3
+ Foundry uses the filesystem for code identity and imported values for code relationships. You should not maintain matching string IDs for static definitions.
4
+
5
+ ## Create and run
6
+
7
+ ```bash
8
+ npx glove foundry support-workforce
9
+ cd support-workforce
10
+ pnpm install
11
+ cp .env.example .env.local
12
+ pnpm dev
13
+ ```
14
+
15
+ `glove foundry dev` discovers the source graph, derives identities, checks types and conventions, generates `.foundry/routes.d.ts`, and starts the runtime and inspector.
16
+
17
+ ## The filesystem is the static registry
18
+
19
+ ```text
20
+ agents/
21
+ lead/
22
+ agent.ts -> agent id: lead
23
+ apps/helpdesk.app.ts -> application id: helpdesk
24
+ transmissions/tickets.transmission.ts -> transmission id: tickets
25
+ predicates/is-urgent.predicate.ts -> predicate id: is-urgent
26
+ connections/ticket-events.connection.ts
27
+ tools/customer-lookup.tool.ts
28
+ mcp/notion.mcp.ts
29
+ memory/customer.memory.ts
30
+ layers/request-context.layer.ts
31
+ subscribers/audit.subscriber.ts
32
+ schedules/daily-review.ts
33
+ ```
34
+
35
+ Nested files produce nested IDs: `tools/calendar/today.tool.ts` becomes `calendar/today`. Every convention file default-exports one definition. That default export is the value other files import and reference.
36
+
37
+ An explicit `id` remains a compatibility escape hatch for programmatic definitions, but the packaged ESLint preset rejects it in normal file-routed authoring.
38
+
39
+ ## Define an agent
40
+
41
+ ```ts
42
+ // agents/lead/agent.ts
43
+ import { MemoryStore } from "glove-core"
44
+ import { createAdapter } from "glove-core/models/providers"
45
+ import { defineAgent } from "glove-foundry"
46
+ import { components } from "./composition.js"
47
+
48
+ export default defineAgent({
49
+ description: "Coordinates customer work",
50
+ components,
51
+ store: ({ conversationId }) => new MemoryStore(`lead:${conversationId}`),
52
+ model: () => createAdapter({
53
+ provider: "openrouter",
54
+ model: process.env.OPENROUTER_MODEL ?? "openai/gpt-4.1-mini",
55
+ }),
56
+ systemPrompt: (_agent, ctx) =>
57
+ `You are the lead. Workspace: ${ctx.workspaceId}. Message: ${ctx.message.text}`,
58
+ tools: (_agent, ctx) =>
59
+ ctx.message.text.includes("customer") ? [customerLookupTool] : [],
60
+ inboxes: (_agent, ctx) => loadInbox(ctx.workspaceId, ctx.agentId),
61
+ })
62
+ ```
63
+
64
+ An agent definition describes lazy assembly. It never declares request input or result output; those are Foundry contracts. An agent definition is also not an instance. Instances are durable data and may be created, updated, removed, or reconstructed independently.
65
+
66
+ ## Define and compose colocated pieces
67
+
68
+ ```ts
69
+ // agents/lead/tools/customer-lookup.tool.ts
70
+ import { defineSharedTool } from "glove-foundry"
71
+ import { Effect } from "effect"
72
+ import { z } from "zod"
73
+
74
+ const customerLookup = defineSharedTool({
75
+ description: "Look up a customer",
76
+ config: z.object({ region: z.string() }),
77
+ create: ({ config }) => Effect.succeed(makeCustomerLookupTool(config.region)),
78
+ })
79
+
80
+ export default customerLookup
81
+ ```
82
+
83
+ ```ts
84
+ // agents/lead/composition.ts
85
+ import { composeAgent } from "glove-foundry"
86
+ import helpdesk from "./apps/helpdesk.app.js"
87
+ import customerLookup from "./tools/customer-lookup.tool.js"
88
+ import customerMemory from "./memory/customer.memory.js"
89
+
90
+ export const components = composeAgent(helpdesk, customerLookup, customerMemory)
91
+ ```
92
+
93
+ `composeAgent` builds the agent-local catalogue. It does not install applications, MCPs, or shared tools. An instance selects those dynamically.
94
+
95
+ ## Mount a working environment, VFS, and REPL
96
+
97
+ Foundry mounts the native Glove packages; it does not reimplement their sandboxes. A working environment supplies a persistent virtual filesystem, named scripts, checkpoints, history, artifact export, and a closed model-facing verb set. A REPL is a separate computation surface over registered functions.
98
+
99
+ ```bash
100
+ pnpm add glove-working-environment glove-js
101
+ # Use glove-python or glove-lisp instead when that is the better agent surface.
102
+ ```
103
+
104
+ ```ts
105
+ // agents/lead/workbench.ts
106
+ import { JsSession, defineFn } from "glove-js"
107
+ import {
108
+ defineRepl,
109
+ defineWorkingEnvironment,
110
+ foundryDataEnvironmentPersistence,
111
+ } from "glove-foundry"
112
+ import { z } from "zod"
113
+
114
+ export const workspace = defineWorkingEnvironment({
115
+ options: ({ assembly }) => ({
116
+ limits: { maxVfsBytes: 64 * 1024 * 1024 },
117
+ onVerb: event => assembly.controls.emit({
118
+ type: "lead.workspace.verb",
119
+ data: event,
120
+ }),
121
+ }),
122
+ persistence: foundryDataEnvironmentPersistence({ scope: "agent" }),
123
+ })
124
+
125
+ export function createRepl(actor: string) {
126
+ const session = JsSession.create({ actor })
127
+ session.register(defineFn({
128
+ name: "customers__active",
129
+ description: "List active customers",
130
+ input: z.object({ region: z.string().optional() }),
131
+ readOnlyHint: true,
132
+ handler: input => customerAdapter.listActive(input),
133
+ }))
134
+ return defineRepl({
135
+ language: "javascript",
136
+ session,
137
+ mount: { discovery: "auto" },
138
+ })
139
+ }
140
+ ```
141
+
142
+ ```ts
143
+ // agents/lead/agent.ts
144
+ export default defineAgent({
145
+ workingEnvironment: workspace,
146
+ repl: (_agent, ctx) =>
147
+ ctx.messageText.includes("analyse") ? createRepl(ctx.agentId) : undefined,
148
+ run: async (_agent, ctx) => {
149
+ await ctx.vfs?.writeFile("/tmp/request.txt", ctx.messageText)
150
+ return ctx.defaultRun()
151
+ },
152
+ // model, prompt, and other surfaces...
153
+ })
154
+ ```
155
+
156
+ `workingEnvironment` and `repl` accept the same direct-value-or-lazy-resolver shape as the other assembly fields. JavaScript, Python, and Lisp sessions are supported through one discriminated `defineRepl` API. Foundry exposes the mounted `workingEnvironment`, its guarded `vfs` handle, and the native `repl` session to layers, `configure`, calls, and `run` handlers.
157
+
158
+ The working environment is closed after every Foundry run. Add a persistence adapter to restore its VFS on the next run. `foundryDataEnvironmentPersistence` uses the data adapter's private snapshot seam, derives ownership from the definition and instance or conversation, and never exposes VFS contents as workspace entries. It requires a durable `FoundryDataAdapter` shared by execution workers. For high-concurrency or large trees, provide a native persistent `Vfs` such as `cachedRemote` in the environment options and let that adapter own locking and storage credentials.
159
+
160
+ REPL bindings persist for the duration of the assembled run. Glove's native REPL packages intentionally do not define a cross-process snapshot format, so durable artifacts belong in the working environment VFS rather than hidden interpreter variables.
161
+
162
+ ## Definitions reference definitions
163
+
164
+ Keep each transmission primitive atomic:
165
+
166
+ ```ts
167
+ // agents/lead/predicates/is-urgent.predicate.ts
168
+ import { Effect } from "effect"
169
+ import { defineTransmissionPredicate } from "glove-foundry"
170
+
171
+ export default defineTransmissionPredicate({
172
+ match: (event: { priority: number }, parameters) =>
173
+ Effect.succeed(event.priority >= Number(parameters.minimum ?? 1)),
174
+ })
175
+ ```
176
+
177
+ ```ts
178
+ // agents/lead/events/ticket-created.event.ts
179
+ import { defineTransmissionEvent } from "glove-foundry"
180
+
181
+ export default defineTransmissionEvent({ direction: "inbound" })
182
+
183
+ // agents/lead/actions/resolve.action.ts
184
+ import { definePlaybookAction } from "glove-foundry"
185
+
186
+ export default definePlaybookAction({
187
+ description: "Resolve the event that activated the playbook",
188
+ })
189
+ ```
190
+
191
+ ```ts
192
+ // agents/lead/transmissions/tickets.transmission.ts
193
+ import { Effect, Schema } from "effect"
194
+ import { defineTransmission } from "glove-foundry"
195
+ import ticketCreated from "../events/ticket-created.event.js"
196
+ import isUrgent from "../predicates/is-urgent.predicate.js"
197
+
198
+ const tickets = defineTransmission({
199
+ name: "Tickets",
200
+ description: "Ticket provider contract",
201
+ events: [ticketCreated],
202
+ account: {
203
+ required: true,
204
+ metadata: Schema.Struct({ workspace: Schema.String }),
205
+ },
206
+ inbound: {
207
+ config: Schema.Struct({ queue: Schema.String }),
208
+ event: Schema.Struct({
209
+ id: Schema.String,
210
+ threadId: Schema.String,
211
+ priority: Schema.Number,
212
+ body: Schema.String,
213
+ }),
214
+ classify: () => Effect.succeed(ticketCreated),
215
+ predicates: [isUrgent],
216
+ },
217
+ outbound: {
218
+ config: Schema.Struct({ queue: Schema.String }),
219
+ input: Schema.Struct({ threadId: Schema.String, body: Schema.String }),
220
+ output: Schema.Struct({ messageId: Schema.String }),
221
+ adapter: { deliver: (input) => userTicketAdapter.deliver(input) },
222
+ },
223
+ })
224
+
225
+ export default tickets
226
+ ```
227
+
228
+ ```ts
229
+ // agents/lead/apps/helpdesk.app.ts
230
+ import { defineApp } from "glove-foundry"
231
+ import tickets from "../transmissions/tickets.transmission.js"
232
+ import ticketEvents from "../connections/ticket-events.connection.js"
233
+
234
+ export default defineApp({
235
+ description: "Ticket application",
236
+ inbound: [tickets],
237
+ outbound: [tickets],
238
+ connections: [ticketEvents],
239
+ })
240
+ ```
241
+
242
+ The application can own multiple inbound and outbound transmissions. Installing it mounts outbound transmissions as validated tools. Connections remain dormant until an active instance or subscription needs the installed app and playbook.
243
+
244
+ ## Config is inferred from its definition
245
+
246
+ Zod config schemas flow into `install`, layer and memory selection, and the install callback:
247
+
248
+ ```ts
249
+ const helpdesk = defineApp({
250
+ description: "Ticket application",
251
+ config: z.object({ queue: z.string(), retries: z.number().default(2) }),
252
+ install: ({ config }) => {
253
+ config.queue // string
254
+ config.retries // number
255
+ return Effect.void
256
+ },
257
+ })
258
+
259
+ install(helpdesk, { queue: "support" }) // valid
260
+ install(helpdesk, { queue: 42 }) // TypeScript error
261
+ ```
262
+
263
+ Effect transmission schemas flow into account metadata, route config, inbound events, outbound inputs, and outbound outputs. Use `configureLayer(layer, config)` and `configureMemory(memory, config)` when those definitions expose config schemas. `defineConfig({...})` rejects unknown top-level and nested framework keys while retaining the exact inferred value type.
264
+
265
+ Runtime decoding still runs at every persistence or execution boundary; TypeScript is not the only validator.
266
+
267
+ ## Runtime topology is data
268
+
269
+ Accounts, routes, bindings, agent instances, and conversations are data records. Their IDs are not static code identities: a UI or adapter may create and update them, so their IDs remain explicit.
270
+
271
+ ```ts
272
+ // agents/lead/topology.ts
273
+ import { defineAccount, defineInboundRoute } from "glove-foundry"
274
+ import tickets from "./transmissions/tickets.transmission.js"
275
+
276
+ export const supportAccount = defineAccount({
277
+ id: "support-account",
278
+ transmission: tickets,
279
+ externalAccountId: "support-team",
280
+ accessRef: "my-adapter://support-team",
281
+ metadata: { workspace: "support" },
282
+ })
283
+
284
+ export const ticketInbound = defineInboundRoute({
285
+ id: "ticket-inbound",
286
+ transmission: tickets,
287
+ account: supportAccount,
288
+ visibility: "workspace",
289
+ enabled: true,
290
+ config: { queue: "support" }, // inferred from tickets.inbound.config
291
+ })
292
+ ```
293
+
294
+ `accessRef` is opaque to Foundry. Credential acquisition and refresh belong to the user-owned account-session adapter.
295
+
296
+ ## Runtime-composed playbooks and dynamic installations
297
+
298
+ ```ts
299
+ // agents/lead/agent.ts
300
+ import { composePlaybook, defineAgent } from "glove-foundry"
301
+ import resolve from "../actions/resolve.action.js"
302
+ import helpdesk from "../apps/helpdesk.app.js"
303
+ import ticketCreated from "../events/ticket-created.event.js"
304
+ import isUrgent from "../predicates/is-urgent.predicate.js"
305
+ import tickets from "../transmissions/tickets.transmission.js"
306
+ import { supportAccount, ticketInbound } from "../topology.js"
307
+
308
+ export default defineAgent({
309
+ description: "Support lead",
310
+ playbooks: (_agent, ctx) => [composePlaybook({
311
+ name: "urgent-ticket",
312
+ transmission: tickets,
313
+ match: {
314
+ event: ticketCreated,
315
+ routes: [ticketInbound],
316
+ predicate: { definition: isUrgent, parameters: { minimum: ctx.agentInstance.context.minimum ?? 3 } },
317
+ },
318
+ directives: [{ action: resolve, instruction: "Investigate and respond." }],
319
+ applications: [helpdesk],
320
+ })],
321
+ // model and other surfaces...
322
+ })
323
+ ```
324
+
325
+ ```ts
326
+ import { defineAgentInstance, install } from "glove-foundry"
327
+ import lead from "./agent.js"
328
+ import helpdesk from "./apps/helpdesk.app.js"
329
+
330
+ export const leadInstance = defineAgentInstance(lead, {
331
+ workspaceId: "support",
332
+ installations: [install(helpdesk, { queue: "support", retries: 3 })],
333
+ playbooks: [], // populated by the lazy agent resolver on its first assembly
334
+ })
335
+ ```
336
+
337
+ `composePlaybook` is called at runtime, not exported as a static playbook definition. Foundry derives the playbook id, converts direct primitive references into a value-only record, and reconciles it onto the instance. A frontend can also provide instance playbook data directly; definition-origin policy and frontend-origin policy remain distinguishable.
338
+
339
+ ## Background activation without an existing instance
340
+
341
+ ```ts
342
+ const [urgentTicket] = persistedAgent.playbooks
343
+ await runtime.putPlaybookSubscription({
344
+ id: subscriptionId,
345
+ workspaceId: persistedAgent.workspaceId,
346
+ enabled: true,
347
+ playbook: urgentTicket,
348
+ targets: runtimeSelectedTargets,
349
+ createdAt: now,
350
+ updatedAt: now,
351
+ })
352
+ ```
353
+
354
+ The subscription is evaluated even when no matching instance exists. A matching inbound event can atomically provision one or many subscribed agents, create their conversations, and start their runs.
355
+
356
+ ## Agent-local schedules and future work
357
+
358
+ ```ts
359
+ const dailyReview = defineSchedule({
360
+ name: "daily-review",
361
+ timing: { kind: "cron", expression: "0 9 * * 1-5", timezone: "UTC" },
362
+ message: "Review unresolved support work.",
363
+ })
364
+
365
+ export default defineAgent({
366
+ schedules: (_agent, ctx) => ctx.agentInstance.context.paused ? [] : [dailyReview],
367
+ // ...
368
+ })
369
+ ```
370
+
371
+ ```ts
372
+ // A running agent uses the framework-owned tool:
373
+ glove_foundry_schedule({
374
+ message: "Review open support work.",
375
+ timing: { kind: "every", interval: "24h" },
376
+ })
377
+
378
+ // Suspend this conversation and wake the same instance later:
379
+ glove_foundry_sleep({
380
+ kind: "for",
381
+ duration: "20m",
382
+ message: "Check whether the deployment has finished, then resolve it.",
383
+ })
384
+
385
+ glove_foundry_schedules({ action: "list" })
386
+ glove_foundry_schedules({ action: "update", activationId, timing: { kind: "every", interval: "2h" } })
387
+ glove_foundry_schedules({ action: "cancel", activationId })
388
+ ```
389
+
390
+ Schedules are agent-local composable values; Foundry has no root schedule registry or automatically discovered schedule files. Immediate spawning, future activation, recurrence, management, and suspension are separate runtime operations. Foundry stores activation state through `FoundryDataAdapter` before arming its private execution backend, so a durable adapter can reconstruct pending work on startup. Sleep preserves the instance and conversation so the wake-up resumes with the same stored context.
391
+
392
+ ## Boundary checklist
393
+
394
+ - Static code identity comes from the convention filename.
395
+ - Static code relationships use imported values.
396
+ - IDs appear when definitions are serialized into durable data.
397
+ - Runtime data IDs remain explicit because users and adapters create those records.
398
+ - Applications, shared tools, and MCPs mount only when an instance installs them.
399
+ - Memory and inboxes are agent-definition surfaces and may resolve from current context/message.
400
+ - Working environments and one native REPL are agent-definition surfaces and may resolve from current context/message.
401
+ - VFS persistence, remote storage, and locking remain adapter-owned.
402
+ - Transmissions own executable integration logic; playbooks remain serializable policy.
403
+ - Provider adapters own credential acquisition and refresh.
@@ -0,0 +1,89 @@
1
+ # Evaluation checklist
2
+
3
+ Use this when deciding whether Foundry has the structure you want.
4
+
5
+ ## Run the evidence
6
+
7
+ ```bash
8
+ pnpm --filter glove-foundry typecheck
9
+ pnpm --filter glove-foundry test
10
+ pnpm --filter glove-foundry build
11
+ pnpm --filter glove-foundry-example typecheck
12
+ pnpm --filter glove-foundry-example verify:architecture
13
+ pnpm --filter glove-foundry-example verify
14
+ ```
15
+
16
+ The package tests include an inbound subscription with zero initial instances, two targets, per-thread provisioning, connection activation, and duplicate-event idempotency.
17
+
18
+ ## Definition and instance boundary
19
+
20
+ - [ ] `defineAgent` produces a reusable data structure, not an invocation contract.
21
+ - [ ] The file route is the definition route.
22
+ - [ ] Instances are stored independently with workspace, context, installations, and playbooks.
23
+ - [ ] An instance can be updated and reconstructed without modifying code.
24
+ - [ ] One instance can own multiple conversations.
25
+ - [ ] Every run assembles from current instance data and the current native Glove message.
26
+
27
+ ## Reference safety
28
+
29
+ - [ ] Code-authored routes use `transmission`, `account`, and other imported values.
30
+ - [ ] Runtime-composed playbooks use transmission, predicate, route, app, and account values.
31
+ - [ ] Playbooks are produced by lazy agent resolvers or runtime data, never file-discovered definitions.
32
+ - [ ] Schedules are agent-local composable values, never a root registry.
33
+ - [ ] Code-authored installations use `install(definition, config)`.
34
+ - [ ] String ids appear only in JSON-safe persisted/API records or inherently dynamic selections.
35
+ - [ ] Reconstruction validates and freezes stored records.
36
+
37
+ ## Composition and installation
38
+
39
+ - [ ] Tools, applications, MCPs, memory, inboxes, layers, subscribers, working environments, and REPLs can be colocated under an agent.
40
+ - [ ] Components are functionally returnable and composable.
41
+ - [ ] Applications and MCPs remain inert until instance data installs them.
42
+ - [ ] Memory belongs to the definition and can be selected lazily.
43
+ - [ ] Inboxes are always lazy functions.
44
+ - [ ] Assembly can depend on current message, conversation, instance, and workspace.
45
+
46
+ ## Applications and transmissions
47
+
48
+ - [ ] An app owns multiple inbound and outbound transmissions.
49
+ - [ ] Installing an app mounts outbound transmission tools.
50
+ - [ ] Transmissions own authentication, normalization, classification, predicates, serialization, and delivery.
51
+ - [ ] Playbooks contain serializable match parameters and directives only.
52
+ - [ ] Credential acquisition and refresh remain in user adapters.
53
+ - [ ] Account metadata exposed by Foundry contains no secret values.
54
+
55
+ ## Background activation
56
+
57
+ - [ ] A durable playbook subscription is evaluated with zero matching instances.
58
+ - [ ] One inbound event can target one or many agent definitions.
59
+ - [ ] `singleton`, `per-thread`, `per-event`, `existing`, and `custom` policies are supported.
60
+ - [ ] Provisioning keys are enforced atomically by the data adapter.
61
+ - [ ] Duplicate route/event deliveries return the original run ids.
62
+ - [ ] A failed dispatch releases its claim for a safe retry.
63
+
64
+ ## Provider workers
65
+
66
+ - [ ] Provider listeners are defined as application connections.
67
+ - [ ] Connections start only for active installed-app/playbook requirements.
68
+ - [ ] Connections receive only safe account metadata, routes, identity, abort, ready, receive, and optional account-session access.
69
+ - [ ] Retry and supervision are observable without exposing backend worker primitives.
70
+ - [ ] Public config, client methods, API routes, manifests, generated declarations, and inspector copy contain no backend deployment concepts.
71
+
72
+ ## Runtime primitives
73
+
74
+ - [ ] Conversations, workspace entries, shared inbox items, tasks, and scoped environment values are first-class adapter data.
75
+ - [ ] Agent-local schedules reconcile into adapter data; agents can also create triggers dynamically.
76
+ - [ ] Core tools can list, update, cancel, recur, sleep, run in background, and reconvene within agent identity.
77
+ - [ ] Layered agents, S2S/S2V calls, mesh, custom subscribers, custom build, and custom run/handler functions remain available.
78
+ - [ ] A native working environment mounts its guarded VFS and script tools with lifecycle cleanup and telemetry.
79
+ - [ ] JavaScript, Python, and Lisp REPLs mount through one typed, lazy agent field.
80
+ - [ ] VFS persistence and storage credentials remain behind user-selectable adapters.
81
+
82
+ ## Developer experience
83
+
84
+ - [ ] `npx glove foundry` scaffolds a type-checking project.
85
+ - [ ] `.foundry/routes.d.ts` provides typed file routes.
86
+ - [ ] ESLint checks Foundry conventions.
87
+ - [ ] The inspector makes arrival → policy → workforce → work visible.
88
+ - [ ] Raw trace data is available without making it the default interface.
89
+ - [ ] The runnable example uses the same public API described in the docs.
@@ -0,0 +1,67 @@
1
+ # Glove Foundry implementation backlog
2
+
3
+ This file records accepted architectural gaps and their implementation status.
4
+
5
+ ## Completed — filename-owned definitions and typed config flow
6
+
7
+ Status: implemented across discovery, isolated execution, the scaffold, ESLint,
8
+ the reference application, and persistence reconstruction.
9
+
10
+ - convention files default-export one definition and derive nested identities
11
+ from their path;
12
+ - imported definition objects are the only code-authoring reference mechanism;
13
+ - isolated agent processes repeat discovery binding before assembly;
14
+ - instance/playbook/subscription seeds defer serialization until identities are
15
+ bound;
16
+ - Zod installation schemas infer `install(...)` input and decoded callback
17
+ config;
18
+ - Effect transmission schemas infer account metadata and inbound/outbound route
19
+ config;
20
+ - `defineConfig` rejects unknown framework keys while preserving exact types;
21
+ - runtime/data records retain explicit IDs because they are dynamically
22
+ provisioned and editable; and
23
+ - the recommended ESLint preset rejects explicit IDs on static file-routed
24
+ definitions.
25
+
26
+ ## Completed — Playbook subscriptions activate agents without pre-existing instances
27
+
28
+ Status: implemented in the runtime and memory data adapter.
29
+
30
+ The inbound dispatcher evaluates both instance playbooks and independent,
31
+ durable `PlaybookSubscription` records. A subscription can activate work when
32
+ no `AgentInstance` exists.
33
+
34
+ Implemented behavior:
35
+
36
+ - persist playbook subscriptions independently from materialized agent
37
+ instances;
38
+ - let a subscription target one or more agent definition routes;
39
+ - resolve existing instances or atomically provision instances from persisted
40
+ data when a matching inbound transmission arrives;
41
+ - support explicit provisioning policies such as singleton, per-thread,
42
+ per-event, fixed fan-out, and a user-supplied provisioning adapter;
43
+ - create or reuse the appropriate conversation before dispatching each run;
44
+ - make inbound retries idempotent across event matching, instance provisioning,
45
+ conversation creation, and run enqueueing;
46
+ - keep executable predicates on transmission definitions and keep playbooks and
47
+ subscriptions serializable;
48
+ - emit observable match, provisioning, fan-out, and dispatch events without
49
+ exposing backend execution-engine terminology.
50
+
51
+ The intended flow is:
52
+
53
+ ```text
54
+ inbound event
55
+ -> authenticate, normalize, and classify through its transmission
56
+ -> query persisted playbook subscriptions
57
+ -> evaluate named transmission predicates
58
+ -> resolve or provision every subscribed agent instance
59
+ -> create or reuse conversations
60
+ -> reconstruct each agent from persisted instance data
61
+ -> enqueue one run per resolved subscription target
62
+ ```
63
+
64
+ The package test suite covers zero pre-existing instances, one-to-many fan-out,
65
+ connection activation, and duplicate delivery. Production adapters must
66
+ implement the same atomic `provisionAgent` and inbound-delivery claim contract;
67
+ adapter-specific restart/concurrency tests belong with those adapters.
@@ -0,0 +1,56 @@
1
+ # Foundry inspector
2
+
3
+ The development server includes a read-oriented runtime inspector. It is organized around Foundry's actual ownership boundaries rather than presenting every event on one screen.
4
+
5
+ ## Navigation
6
+
7
+ | Page | Question it answers |
8
+ | --- | --- |
9
+ | Overview | Is the runtime healthy, what is active, and what needs attention? |
10
+ | Agents | Which definitions exist, which instances were provisioned, and how do they differ? |
11
+ | Agent definition | What can this code route assemble, including lazy fields, capabilities, native surfaces, schedules, and playbooks? |
12
+ | Agent instance | Which context, installations, playbooks, conversations, and runs belong to this persisted identity? |
13
+ | Runs | Which invocations occurred and what status, source, and attempt count did each have? |
14
+ | Run detail | What observable phases and events produced this outcome? |
15
+ | Automations | Which schedules, sleeping runs, playbook listeners, and inbound application workers exist? |
16
+ | Integrations | Which transmissions, safe account references, routes, and agent bindings form the external topology? |
17
+ | Workspaces | Which shared entries, inbox items, tasks, and non-secret environment values are available? |
18
+
19
+ Every detail view has a real URL. For example, `/agents/support-lead`, `/instances/<agent-id>`, and `/runs/<run-id>` can be bookmarked or opened directly; the Foundry server returns the inspector shell for non-API paths.
20
+
21
+ ## Following a run
22
+
23
+ Open **Runs**, then choose one invocation. The run detail starts with a four-phase spine:
24
+
25
+ 1. Accepted: Foundry persisted the invocation and its source.
26
+ 2. Assembled: context-dependent agent components were resolved and mounted.
27
+ 3. Agent work: observable model and tool work occurred.
28
+ 4. Completed, failed, cancelled, or still in progress.
29
+
30
+ The event trace below the spine is collapsed by default. Expand an event when you need its adapter payload. The inspector shows observable intent, actions, and outcomes; it does not expose a model's private hidden chain-of-thought.
31
+
32
+ ## Starting work
33
+
34
+ Use **New run** from any page. Select a definition and either:
35
+
36
+ - choose an existing runtime instance; or
37
+ - let Foundry create a new instance in the current/default workspace.
38
+
39
+ The inspector reuses that instance's latest conversation or creates its first conversation, sends the message, then navigates directly to the new run.
40
+
41
+ ## Live updates and search
42
+
43
+ The inspector subscribes to `/api/events` with server-sent events and also performs a low-frequency reconciliation. Press `Command-K` or `Control-K` to search pages, definitions, instances, and retained runs.
44
+
45
+ ## Operator API used by the inspector
46
+
47
+ The inspector is an API client and adds no hidden runtime state. Its primary read surfaces are:
48
+
49
+ - `/api/manifest`, `/api/agent-instances`, and `/api/conversations`
50
+ - `/api/runs`, `/api/runs/:id`, and `/api/events`
51
+ - `/api/activations` and `/api/playbook-subscriptions`
52
+ - `/api/application-connections`
53
+ - `/api/transmissions`, `/api/accounts`, `/api/routes`, and `/api/bindings`
54
+ - `/api/workspaces/:id/entries|inbox|tasks|environment`
55
+
56
+ `/api/activations` exposes persisted schedule and sleep records, optionally filtered with `?workspace=<id>`. Like the rest of Foundry's operator API, it contains runtime metadata, not credential material.