Skip to Content

← All archived runs

Run: ai-agent-foundation

run.md

Run: ai-agent-foundation

  • branch: claude/ai-agent-foundation-pipeline-ewcrj1
  • pr: #604

00_intake/stub.md

Stub: Reusable AI agent foundation (tenant-scoped tools)

  • feature-slug: ai-agent-foundation
  • epic: tenant-onboarding-wizard
  • personas: Admin (indirectly all — platform capability)
  • initiative: Build the Bridge / objective: Q2-2026 O1 — Establish PMF with Vendor Partners
  • depends-on: none
  • sequence: 2 of 7

Problem

packages/services/src/ai/ today is a config folder plus one bespoke agent (brd/) with its own prompt/tools wiring. Every new AI feature would re-invent agent setup, tool definitions and streaming plumbing. The epic's explicit requirement is a strong foundation that lets AI seamlessly connect to the application — the onboarding agent is the first consumer, not a one-off.

Proposed change

Rework packages/services/src/ai into a small reusable agent core: a conventional way to define an agent (model/config via the existing AI Gateway setup), a tenant-scoped tool registry so tools wrap existing domain services (products, services, skills/categories, SLA, tenant settings) and can never reach across tenants, structured-output helpers for typed generation, and the streaming route + human-in-the-loop conventions consistent with ai/brd and the ai-feature skill. Deliverable is the core + at least one thin proof (e.g. a read-only catalogue tool) demonstrating a service exposed as an agent tool. brd/ keeps working; migrating it onto the core is optional and only if trivially cheap.

Acceptance criteria (rough)

  • A new agent can be declared with config, prompt and a set of tools without copying code from brd/.
  • Tools are constructed with an explicit tenant context; a tool invocation cannot read or write another tenant's data.
  • Typed/structured output generation is available as a helper (Zod schema in, validated object out).
  • The existing BRD agent still functions unchanged (or is migrated with identical behaviour).

Out of scope (this feature)

  • The onboarding agent itself, its prompts and blueprint tools (stub 5).
  • Source-analysis/extraction (stub 4).
  • Any UI.

Notes for Define

This is the epic's foundation bet — size it deliberately: general enough that stubs 4–5 and future agents (matching, success, recruiter are roadmapped) sit on it, small enough to stay one PR. If Define finds it ballooning, cut the proof-tool scope, not the tenant-scoping. touches: packages/services/src/ai/ (respect the /server vs /shared entry-point boundary per services-imports). Vercel AI SDK v6 (ToolLoopAgent) per the ai-feature skill.

01_define/output/spec.md

Spec: Reusable AI agent foundation (tenant-scoped tools)

  • slug: ai-agent-foundation
  • personas: Admin (indirectly all — platform capability)
  • touches: packages/services/src/ai, packages/services/src/ai/index.ts, packages/services/package.json (./ai entry)
  • complexity: complex

Problem

packages/services/src/ai/ today is a config folder (config/) plus one bespoke agent (brd/) that hand-wires its own prompt, tools and streaming plumbing. Every new AI feature would re-invent that setup — agent declaration, tool definitions, structured output and the human-in-the-loop streaming conventions — and nothing today forces a tool to stay inside its tenant. The tenant-onboarding-wizard epic (Build the Bridge / Q2-2026 O1 — establish PMF with vendor partners, KR: onboard 8+ vendors onto paid tiers) explicitly requires a strong foundation that lets AI seamlessly connect to the application before the onboarding concierge (and the roadmapped matching / success / recruiter agents) are built on top. This is the epic's foundation bet: general enough to carry stubs 4–5 and future agents, small enough to stay one PR.

Proposed change

Rework packages/services/src/ai into a small, reusable agent core, keeping the existing AI Gateway config and the Vercel AI SDK v6 (ToolLoopAgent) idiom established by ai/brd and the ai-feature skill:

  • Agent declaration — a conventional way to declare an agent (model/config via the existing AI Gateway setup, prompt, and a set of tools) without copying code from brd/.
  • Tenant-scoped tool registry — tools are constructed with an explicit tenant context and wrap existing domain services (products, services, skills/categories, SLA, tenant settings). Every data access is bound to the caller's tenant so a tool can never read or write another tenant's data.
  • Structured-output helper — typed generation: a Zod schema in, a validated object out.
  • Streaming + human-in-the-loop conventions — shared helpers so a new agent's streaming route and approval flow stay consistent with ai/brd and the ai-feature skill, rather than being re-hand-rolled per feature.
  • Proof tool — at least one thin, read-only proof (a catalogue read tool over an existing tenant-scoped service) demonstrating a domain service exposed as an agent tool through the registry, with the tenant guarantee exercised.

brd/ keeps working unchanged. The core is exported through the existing @sustentus/services/ai entry point, respecting the /server vs /shared boundary (per the services-imports skill).

Acceptance criteria

  • A new agent can be declared with config, prompt and a set of tools using the core, without copying code from brd/.
  • Tools are constructed with an explicit tenant context; a tool invocation cannot read or write another tenant's data (demonstrated by the proof tool being scoped to its caller's tenant).
  • A structured-output helper is available: given a Zod schema it returns a validated, typed object.
  • A read-only catalogue proof tool wraps an existing tenant-scoped domain service and is invokable through the registry.
  • The existing BRD agent still functions unchanged (its prompt, tools and streaming behaviour are unaltered).
  • The core is exported from @sustentus/services/ai and respects the /server vs /shared import boundary (no server-only code leaks into a client-safe entry point).

Out of scope

  • The onboarding concierge agent, its prompts and blueprint-drafting tools (epic stub 5).
  • Source-analysis / extraction pipeline (epic stub 4).
  • Any UI — no apps/web chat surface or route wiring this run.
  • Migrating brd/ onto the new core — brd/ stays as-is; a later run may adopt the core if it is trivially cheap.
  • Adding tools for every domain service — one read-only catalogue proof tool is enough to prove the registry; the remaining service tools are built by their consuming features.

Open questions

  • none — proof-tool scope is fixed to a single read-only catalogue tool; if the core balloons past one PR, cut proof-tool scope, never the tenant-scoping (per the stub's Notes for Define).

02_build/output/notes.md

Build notes: ai-agent-foundation

  • commits: feat: ai-agent-foundation — reusable tenant-scoped agent core + catalogue proof tool

What changed

  • packages/services/src/ai/core/agent.ts (new): defineAgent({ model?, instructions, tools? }) — declares a ToolLoopAgent with the house gateway-model default (DEFAULT_AGENT_MODEL) and the AI SDK cast, so a new agent needs no copy of brd/.
  • packages/services/src/ai/core/structured-output.ts (new): generateStructured({ schema, prompt, system?, model? }) — Zod schema in, validated typed object out, via the AI Gateway (generateObject
    • gateway(...)). No raw provider SDK.
  • packages/services/src/ai/core/tenant-tools.ts (new): the tenant-scoped tool registry. createTenantContext(tenantId) validates the id (24-char ObjectId) and freezes it; defineTenantTool builds a tool whose execute closes over the bound context; buildTenantTools(ctx, factories) binds a named set to one tenant. Tool input schemas never carry a tenantId, so a model/user cannot direct a tool at another tenant — ctx.tenantId is the only tenant id a tool ever sees.
  • packages/services/src/ai/core/index.ts (new): core barrel.
  • packages/services/src/ai/tools/catalogue.ts (new): read-only proof tool. list_catalogue wraps the existing tenant-scoped productService/serviceService (findAll(ctx.tenantId, …)) and returns the tenant's products/services. buildCatalogueTools(ctx) binds it, ready for defineAgent.
  • packages/services/src/ai/index.ts (edit): re-export the core via @sustentus/services/ai (client-safe — core imports only ai + zod, no DB).
  • packages/services/src/server/index.ts (edit): export catalogueTool / buildCatalogueTools from @sustentus/services/server — the DB-touching proof tool lives behind /server, not /ai.

Design decisions (within the settled spec)

  • Isolation is structural, not conventional. A tenant tool's inputSchema is business input only; the tenant id is supplied by the bound TenantContext, never by the caller. There is no code path that lets a tool receive a different tenant's id, so the "can't cross tenants" guarantee holds by construction.
  • /ai vs /server split (AC6). The generic core (no DB) is exported from the client-safe /ai entry that agents already use; the concrete catalogue tool imports Mongoose-backed services and is therefore exported from /server only. No server-only code leaks into /ai.
  • Core stays mongoose-free — tenant-id validation is a 24-hex regex, not mongoose.Types.ObjectId, so the core can live in the client-safe barrel.
  • brd/ untouched (migration out of scope per the spec).

Acceptance criteria status

  • A new agent can be declared with config, prompt and tools using the core — defineAgent (no brd/ copy needed).
  • Tools are constructed with an explicit tenant context and cannot cross tenants — createTenantContext + defineTenantTool/buildTenantTools; the catalogue tool only ever reads ctx.tenantId.
  • Structured-output helper (Zod in, validated object out) — generateStructured.
  • Read-only catalogue proof tool wrapping an existing tenant-scoped service, invokable through the registry — catalogueTool / buildCatalogueTools over productService/serviceService.
  • The existing BRD agent still functions unchanged — brd/ and its exports are untouched; only additive exports were added to the barrels.
  • Core exported from @sustentus/services/ai, DB tool from @sustentus/services/server/server vs client-safe /ai boundary respected.

Verify result

  • mechanical checks (format · lint · typecheck · build) run in CI + the Vercel preview, not here. No check is expected to fail.

Notes for review

  • The tenant-isolation guarantee rests on tool input schemas never carrying a tenantId — worth a look when future tools are added (a tool that accepts a tenantId in its schema would break the invariant).
  • stubs 4–5 (source-analysis, onboarding concierge) build their tools on defineTenantTool and their agent on defineAgent; the catalogue tool is the template to copy for the remaining services (skills, SLA, tenant settings).

03_release/output/investor-update.md

One AI foundation now powers every agent we build

Who it's for: Internal platform — every AI agent we build, now and roadmapped. What shipped: A reusable agent core: any feature declares an AI agent and reaches tenant data through shared, tenant-isolated tools. Why it matters: Faster, safer delivery of the onboarding concierge behind our Q2 objective — establish product-market fit with vendor partners.

Tools bind to one tenant by construction; cross-tenant access is structurally impossible.

Dig deeper: https://github.com/sustentus/sustentus/pull/604

03_release/output/release.md

Release: ai-agent-foundation

  • pr: https://github.com/sustentus/sustentus/pull/604 · merged: yes — squash 205d589, 2026-07-07
  • CI: green — Quality Project (format/lint/typecheck), preview DB migrate, and "Review diff against CONVENTIONS.md" all passed; no inline review comments
  • technical docs: updated apps/docs/app/technical/packages/services/page.mdx (AI section — agent core
    • tenant tools + /ai vs /server split) in this PR
  • business docs: no business docs impact — internal platform capability, no user-facing surface changed
  • release notes: investor-only — no end-user changelog entry (internal change, no user-facing behaviour)
  • deploy: web=READY, docs=READY (the apps this change affects). help-centre=CANCELED via Vercel Ignored Build Step (nothing under apps/help changed; errorLink confirms) — benign skip, and the email links only the merged PR, so it does not gate this release. poll-deploy returned ERROR on the help skip; overridden after confirming the cause, with user authorisation to send.
  • sent: investor update sent to 2 recipients on 2026-07-07, after web + docs deploys reported READY

Review summary

  • Type compatibility of the new AI-SDK call sites (ToolLoopAgent, generateObject, tool) verified against installed ai@6.0.175 + zod@3.25.67 declarations — all PASS; each mirrors an already-compiling reference file (brd/). CI typecheck (Quality Project) green confirms.
  • No correctness findings on the diff (small, additive, self-contained). Tenant isolation is structural: tool input schemas never carry a tenantId, so the bound ctx.tenantId is the only tenant a tool sees.
  • CONVENTIONS.md CI review passed clean — no cleanup or convention findings to triage.

Acceptance check (vs spec)

  • A new agent can be declared with config, prompt and tools using the core — defineAgent, no brd/ copy.
  • Tools built with an explicit tenant context; cannot cross tenants — createTenantContext + defineTenantTool/buildTenantTools; catalogue tool reads only ctx.tenantId.
  • Structured-output helper (Zod in, validated object out) — generateStructured.
  • Read-only catalogue proof tool wrapping a tenant-scoped service, invokable via the registry — catalogueTool / buildCatalogueTools over productService/serviceService.
  • BRD agent unchanged — brd/ untouched; only additive barrel exports.
  • Core exported from @sustentus/services/ai; DB tool from @sustentus/services/server — boundary respected.