diff --git a/examples/vc/README.md b/examples/vc/README.md new file mode 100644 index 0000000..42cd88e --- /dev/null +++ b/examples/vc/README.md @@ -0,0 +1,47 @@ +# Venture capital tenant package + +A tenant package for a venture fund, shaped the same way as [`examples/fintech`](../fintech): +five YAML files that describe the coworkers a deployment ships with, the channels they answer in, +the model behind them, and where authorized knowledge is read from. It is configuration, not code. + +Point a deployment at it with `TENANT_PACKAGE_DIR`, resolved from `server/`: + +```sh +TENANT_PACKAGE_DIR=../examples/vc bash scripts/start.sh +``` + +## Coworkers + +| Coworker | Type | Does | +| ------------------- | ------------- | --------------------------------------------------------------------- | +| Deal Scout | built-in | Screens inbound decks and intros, briefs them against the thesis. | +| Diligence Analyst | remote-ag-ui | First-pass market and company diligence on a governed computer. | +| Portfolio Monitor | built-in | Tracks portfolio news, updates, and distress signals. | +| Fund Knowledge | built-in | Answers from thesis, memos, and prior deals, with sources. | +| LP Relations | built-in | Drafts LP updates and answers from authorized fund data. | + +Deal Scout, Portfolio Monitor, Fund Knowledge, and LP Relations are `built-in`: a system prompt and +nothing else. Diligence Analyst is `remote-ag-ui`, so it drives a real browser on its own governed +computer — market sizing, founder and competitor research, red-flag checks — and can hand the wheel +to a person when it reaches a login wall or a check it should not clear alone. Its endpoint is read +from `MANAGED_AGENT_AG_UI_URL`, falling back to the Bot in the box so a clone runs with no +configuration. Swap it for a diligence agent of your own — on any framework, over AG-UI — and +nothing else here changes. + +## Channels and groups + +`channels.yaml` opens each coworker to a set of groups: `partners`, `investment`, and `platform` in +this example. Deal flow, diligence, and LP relations are scoped tighter than portfolio tracking and +fund knowledge. Map these names to your own directory groups, and remember that access to knowledge, +credentials, and browser actions is still governed at `/admin/boundaries` and `/admin/credentials` — +the channel decides who can talk to a coworker, not what it is allowed to do. + +## Before you rely on it + +- The knowledge roots (`Deals`, `Portfolio`, `Thesis`, `LP`, `Fund Operations`) are folder names to + replace with your own. Connect the sources at `/admin/connectors`. +- Keep deal terms, LP identities, and portfolio figures in governed knowledge and credentials, never + in this YAML. The prompts tell each coworker to cite sources and to refuse to invent figures, but + the boundary is what enforces it. +- Add a `theme.css` beside these files to reskin the surface; see + [docs/configuration.md](../../docs/configuration.md). diff --git a/examples/vc/agents.yaml b/examples/vc/agents.yaml new file mode 100644 index 0000000..7b6a3b3 --- /dev/null +++ b/examples/vc/agents.yaml @@ -0,0 +1,81 @@ +# A tenant package for a venture capital fund. Every Bot here is reachable the moment the deployment +# starts, so the surface never registers an endpoint that is unavailable by default. +# +# The coworkers below are configuration, not code. Edit their prompts, add your own, or point one at +# a framework Bot of your own by giving it an `endpoint`. Keep the browser-driving roles governed: +# what a Bot may open, read, and type is decided at /admin/boundaries, not here. +agents: + # Reads inbound decks and forwarded intros and turns them into a short, comparable brief: what the + # company does, stage, round, traction claims, and how it sits against the fund's thesis. It reasons + # over what it is given and cites the fund's own memos; it does not browse. + - id: deal-scout + name: Deal Scout + title: Inbound & Screening + role_description: Triage inbound decks and intros, and brief them against the fund thesis. + avatar_seed: deal-scout + type: built-in + system_prompt: >- + You screen inbound venture deals for a fund. For each company, produce a concise, comparable + brief: what it does in one line, stage and round, the traction and metrics claimed, the team, + and the clearest risks. Judge fit against the fund's thesis and prior memos from authorized + knowledge, and cite every source you use. Never invent metrics, funding amounts, or investor + names: if a figure is not in what you were given, say it is not stated. Separate what the + founder claims from what is verified. End with a recommendation to pass, watch, or advance, and + the single most important open question a partner should ask. + + # Does the reading a first-pass diligence needs, on its own governed computer: founder and company + # background, market size, the competitive set, news and any red flags. It has a real browser, so it + # can reach a login wall or a check it should not clear alone and hand the wheel back to a person. + # Named in dollar-brace form so the address belongs to the deployment; the fallback points at the + # Bot in the box, so a clone runs with no configuration. + - id: diligence-analyst + name: Diligence Analyst + title: Market & Company Diligence + role_description: Run first-pass diligence on a company, its market, and its competitors. + avatar_seed: diligence-analyst + type: remote-ag-ui + endpoint: ${MANAGED_AGENT_AG_UI_URL:-http://localhost:4200/ag-ui} + + # Watches the portfolio: funding, hiring, launches, press, and anything that looks like distress. + # Answers from authorized company knowledge and portfolio documents rather than from memory. + - id: portfolio-monitor + name: Portfolio Monitor + title: Portfolio Tracking + role_description: Track portfolio company news, updates, and signals worth a partner's attention. + avatar_seed: portfolio-monitor + type: built-in + system_prompt: >- + You help a venture fund keep track of its portfolio. From authorized portfolio documents and + updates, summarize what changed for a company, flag anything that looks like a risk or a + milestone, and say plainly when you have no recent information rather than guessing. Cite the + document behind every statement. Do not speculate about valuations or outcomes that are not in + the source. + + # Answers questions from the fund's own record: thesis memos, past deals, market notes, process + # docs. The house historian. + - id: knowledge + name: Fund Knowledge + title: Thesis & Memory + role_description: Answer questions from the fund's thesis, memos, and prior deals, with sources. + avatar_seed: knowledge + type: built-in + system_prompt: >- + You answer questions from a venture fund's authorized knowledge: thesis memos, investment + memos, prior deals, and internal notes. Cite every source. If the answer is not in authorized + knowledge, say so instead of guessing, and never disclose deal terms or LP information to + someone whose channel does not already carry them. + + # Drafts LP-facing material from the fund's own numbers and updates: quarterly notes, answers to LP + # questions, capital-call context. It drafts; a partner sends. + - id: lp-relations + name: LP Relations + title: LP Reporting & Updates + role_description: Draft LP updates and answer LP questions from authorized fund data. + avatar_seed: lp-relations + type: built-in + system_prompt: >- + You draft investor-relations material for a venture fund's limited partners from authorized + fund data: quarterly updates, answers to LP questions, and portfolio summaries. Write in a + measured, factual voice. Use only figures present in authorized sources and cite them; never + estimate returns, mark-ups, or valuations that are not stated. Everything you produce is a + draft for a partner to review and send, not a message to an LP. diff --git a/examples/vc/brand.yaml b/examples/vc/brand.yaml new file mode 100644 index 0000000..8cbd548 --- /dev/null +++ b/examples/vc/brand.yaml @@ -0,0 +1,3 @@ +tenant: + id: venture + product_name: OpenBot for Venture diff --git a/examples/vc/channels.yaml b/examples/vc/channels.yaml new file mode 100644 index 0000000..ad7b8c8 --- /dev/null +++ b/examples/vc/channels.yaml @@ -0,0 +1,33 @@ +# Who can talk to which coworker. Every id in permitted_agents must name an agent in agents.yaml, and +# allowed_groups decides which people the channel is open to. The groups here — partners, investment, +# platform — are an example; map them to your own directory groups. +channels: + - id: deal-flow + name: Deal Flow + description: Screen inbound deals and brief them against the thesis. + permitted_agents: [deal-scout, knowledge] + allowed_groups: [partners, investment] + + - id: diligence + name: Diligence + description: Run first-pass market and company diligence on a governed computer. + permitted_agents: [diligence-analyst, knowledge] + allowed_groups: [partners, investment] + + - id: portfolio + name: Portfolio + description: Track portfolio company news, updates, and signals. + permitted_agents: [portfolio-monitor, knowledge] + allowed_groups: [partners, investment, platform] + + - id: lp-relations + name: LP Relations + description: Draft LP updates and answers from authorized fund data. + permitted_agents: [lp-relations, knowledge] + allowed_groups: [partners] + + - id: fund-knowledge + name: Fund Knowledge + description: Ask the fund's thesis, memos, and prior deals. + permitted_agents: [knowledge] + allowed_groups: [partners, investment, platform] diff --git a/examples/vc/knowledge.yaml b/examples/vc/knowledge.yaml new file mode 100644 index 0000000..256d903 --- /dev/null +++ b/examples/vc/knowledge.yaml @@ -0,0 +1,8 @@ +# Where authorized knowledge is read from. Only google-drive and microsoft-onedrive are supported +# today. roots are the top-level folders a source is allowed to reach; keep them scoped to what the +# coworkers above actually need. Access is still governed per channel and group, not granted here. +sources: + - type: google-drive + roots: [Deals, Portfolio, Thesis] + - type: microsoft-onedrive + roots: [LP, Fund Operations] diff --git a/examples/vc/model.yaml b/examples/vc/model.yaml new file mode 100644 index 0000000..5bdce6a --- /dev/null +++ b/examples/vc/model.yaml @@ -0,0 +1,4 @@ +model: + provider: openai + credential_secret_ref: openai-api-key + default_model: gpt-4.1 diff --git a/tests/vc-package.test.ts b/tests/vc-package.test.ts new file mode 100644 index 0000000..cf7c15d --- /dev/null +++ b/tests/vc-package.test.ts @@ -0,0 +1,38 @@ +import { expect, test } from "bun:test"; +import { existsSync, readFileSync } from "node:fs"; +import { join } from "node:path"; + +const vcDirectory = join(import.meta.dir, "..", "examples", "vc"); + +test("includes the complete venture deployment package example", () => { + for (const fileName of [ + "brand.yaml", + "agents.yaml", + "channels.yaml", + "model.yaml", + "knowledge.yaml", + ]) { + expect(existsSync(join(vcDirectory, fileName))).toBe(true); + } + + expect(readFileSync(join(vcDirectory, "brand.yaml"), "utf8")).toContain( + "id: venture", + ); +}); + +test("names every environment variable with a fallback, so a clone can read it", () => { + // Same property the fintech package holds: a package a checkout can load with no .env. A name here + // without a `:-` fallback would leave a clone unable to read the package. + const agents = readFileSync(join(vcDirectory, "agents.yaml"), "utf8"); + const referenced = [ + ...agents.matchAll(/\$\{([A-Za-z_][A-Za-z0-9_]*)([^}]*)\}/g), + ]; + + expect(referenced.length).toBeGreaterThan(0); + for (const [, name, rest] of referenced) { + expect( + rest.startsWith(":-"), + `\${${name}} in agents.yaml has no fallback, so a clone with no .env cannot read it`, + ).toBe(true); + } +});