-
Notifications
You must be signed in to change notification settings - Fork 20
feat(cli): teach conventions via scaffolded AGENTS.md, drop skill-install from setup prompt #1110
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,200 @@ | ||
| @TESTING.md | ||
| # {{PROJECT_NAME}} — Lobu project guide | ||
|
|
||
| This file is auto-loaded by your coding agent and is the source of truth for how | ||
| to build and run this Lobu project. Follow it — you do not need any separately | ||
| installed skill or plugin. | ||
|
|
||
| ## What Lobu is | ||
|
|
||
| An open-source, event-sourced backend for AI agents: | ||
|
|
||
| - **Connectors** pull from external sources (GitHub, Slack, a website, a webhook, | ||
| a CSV) via scheduled **feeds** that collect incrementally — each run picks up | ||
| only what's new since the last (checkpointed), so nothing is re-ingested — and | ||
| emit **events**. When onboarding a user, explain this model in plain terms before | ||
| writing config so they understand what they're building. | ||
| - **Memory** turns events into a structured, append-only knowledge graph of typed | ||
| **entities** and **relationships**. | ||
| - **Agents** react to messages in real time and answer over chat platforms, HTTP, | ||
| and MCP. | ||
| - **Watchers** are scheduled prompts that read the graph and act (a daily digest, | ||
| inbound triage, etc.). | ||
|
|
||
| `lobu run` boots the whole thing (gateway + worker + memory) as one Node process | ||
| on http://localhost:{{GATEWAY_PORT}}. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Before `lobu run`, the host needs Node 22-24 (25+ is rejected — `isolated-vm` has | ||
| no build) and one LLM provider key in `.env`. Postgres is built in: `lobu run` | ||
| starts an embedded PostgreSQL (with `pgvector`); set `DATABASE_URL` only to use an | ||
| external Postgres instead. If a prerequisite is missing, stop and help the user | ||
| install it — don't work around it. | ||
|
|
||
| ## Layout | ||
|
|
||
| - `lobu.config.ts` — the entire project as TypeScript. Source of truth; the only | ||
| file `lobu apply` reads. | ||
| - `agents/<id>/IDENTITY.md`, `SOUL.md`, `USER.md` — agent persona / behavior / | ||
| user context. | ||
| - `connectors/*.connector.ts` — custom data sources (only when no bundled | ||
| connector fits). | ||
| - `*.reaction.ts` — code a watcher runs after extraction (post to Slack, update | ||
| an entity). | ||
| - `skills/<name>/SKILL.md` — reusable capability bundles for the agent. | ||
| - `.env` — secrets (`DATABASE_URL`, provider keys, OAuth creds). Never commit real | ||
| values; never invent them. | ||
|
|
||
| ## Config API | ||
|
|
||
| Author everything in `lobu.config.ts` with helpers from `@lobu/cli/config`: | ||
| `defineConfig`, `defineAgent`, `defineEntityType`, `defineRelationshipType`, | ||
| `defineWatcher`, `defineConnection`, `defineAuthProfile`, `secret`, plus | ||
| `connectorFromFile`, `reactionFromFile`, `skillFromFile`. | ||
|
|
||
| Read the complete, working reference before editing: | ||
| https://github.com/lobu-ai/lobu/blob/main/examples/lobu-crm/lobu.config.ts | ||
|
|
||
| ### Agent | ||
|
|
||
| ```ts | ||
| const agent = defineAgent({ | ||
| id: "{{PROJECT_NAME}}", | ||
| // dir defaults to ./agents/<id> (where init scaffolds IDENTITY.md / SOUL.md / USER.md) | ||
| name: "{{PROJECT_NAME}}", | ||
| description: "<one sentence: what it does>", | ||
| providers: [ | ||
| { id: "anthropic", model: "anthropic/claude-...", key: secret("ANTHROPIC_API_KEY") }, | ||
| ], | ||
| // skills: [skillFromFile("./skills/<name>")], | ||
| // network: { allowed: ["api.example.com"] }, // egress allowlist | ||
| }); | ||
| ``` | ||
|
|
||
| ### Chat platforms (where people talk to it) | ||
|
|
||
| Where people message the agent is declared on the agent via `platforms`, NOT as a | ||
| `defineConnection` (connections are data sources). Chat-platform `config` values are | ||
| `secret(...)` refs resolved from `.env`. The `rest` platform exposes the HTTP Agent | ||
| API (POST to `/lobu/api/v1/agents/<id>/messages`) and takes an empty `config: {}`: | ||
|
|
||
| ```ts | ||
| const agent = defineAgent({ | ||
| id: "{{PROJECT_NAME}}", | ||
| // ...providers... | ||
| platforms: [ | ||
| { type: "slack", config: { botToken: secret("SLACK_BOT_TOKEN") } }, | ||
| { type: "rest", config: {} }, // HTTP API — no secret needed; always config: {} | ||
| // other chat types: telegram | discord | whatsapp | teams | google_chat | ||
| // Slack only: optional channels: ["<teamId>/<channelId>"] | ||
| ], | ||
| }); | ||
| ``` | ||
|
|
||
| ### Entity types (what it remembers) | ||
|
|
||
| ```ts | ||
| const ticket = defineEntityType({ | ||
| key: "ticket", | ||
| name: "Ticket", | ||
| required: ["subject"], | ||
| properties: { | ||
| subject: { type: "string", "x-table-label": "Subject", "x-table-column": true }, | ||
| status: { type: "string", enum: ["open", "closed"], "x-table-label": "Status", "x-table-column": true }, | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| Each property is a JSON Schema fragment. `"x-table-column": true` surfaces it as a | ||
| column in the admin UI. | ||
|
|
||
| ### Connection (a bundled connector — preferred) | ||
|
|
||
| ```ts | ||
| const ghAuth = defineAuthProfile({ slug: "gh", connector: "github", authKind: "oauth_account", name: "GitHub" }); | ||
|
|
||
| const gh = defineConnection({ | ||
| slug: "github-main", | ||
| connector: "github", | ||
| name: "GitHub", | ||
| authProfile: ghAuth, // declare the profile as a const, then list it in defineConfig({ authProfiles }) | ||
| config: { repo_owner: "you", repo_name: "repo" }, | ||
| feeds: [{ feed: "issues", name: "Issues", schedule: "0 */6 * * *", config: { repo_owner: "you", repo_name: "repo" } }], | ||
| }); | ||
| ``` | ||
|
|
||
| **Bundled connector keys** — use the exact key (Gmail is `google_gmail`, not | ||
| `gmail`): `github`, `google_gmail`, `google_calendar`, `microsoft_outlook`, | ||
| `website`, `rss`, `hackernews`, `reddit`, `x`, `linkedin`, `youtube`, `spotify`, | ||
| `producthunt`, `g2`, `capterra`, `glassdoor`, `trustpilot`, `revolut`, `gmaps`, | ||
| plus on-device connectors (`apple_health`, `apple_photos`, `apple_screen_time`, | ||
| `chrome*`, `local_directory`, `whatsapp_local`). | ||
|
|
||
| Each connector defines its own `config` keys and feed keys — don't guess them. If | ||
| you're unsure of a connector's config shape, ask the user or read its definition; | ||
| `npx @lobu/cli@latest connector run <key> --check` resolves and validates a config | ||
| without executing it. | ||
|
|
||
| If the source has no bundled connector, write `connectors/<name>.connector.ts` | ||
| (model it on `examples/lobu-crm/funnel-form.connector.ts` in the repo) and | ||
| reference it with `connectorFromFile("./connectors/<name>.connector.ts")`. | ||
|
|
||
| ### Auth profiles & secrets | ||
|
|
||
| Integrations authenticate via `defineAuthProfile` (`oauth_account` = the user logs | ||
| in interactively; `oauth_app` = your own OAuth app, creds passed as `secret(...)`). | ||
| Every credential is a `secret("ENV_NAME")` placeholder resolved from `.env` — never | ||
| paste a real key into the config, and never fabricate one. If a secret is missing, | ||
| ask the user to add it to `.env`. | ||
|
|
||
| ### Watcher (scheduled prompt) + reaction | ||
|
|
||
| ```ts | ||
| const digest = defineWatcher({ | ||
| agent, | ||
| slug: "daily-digest", | ||
| name: "Daily digest", | ||
| schedule: "0 9 * * *", // cron | ||
| prompt: "Summarize yesterday's tickets by root cause and post to Slack.", | ||
| extractionSchema: { type: "object", properties: { summary: { type: "string" } } }, | ||
| // reaction: reactionFromFile<typeof reactionMod>("./daily-digest.reaction.ts"), | ||
| }); | ||
| ``` | ||
|
|
||
| No `reaction` → the extracted data is written to memory. A `reaction` lets the | ||
| watcher act (post a message, update entities). | ||
|
|
||
| ### Wire it together | ||
|
|
||
| ```ts | ||
| export default defineConfig({ | ||
| org: "<slug>", | ||
| orgName: "<Display name>", | ||
| agents: [agent], | ||
| entities: [ticket], | ||
| connections: [gh], | ||
| authProfiles: [ghAuth], | ||
| watchers: [digest], | ||
| }); | ||
| ``` | ||
|
|
||
| ## Commands | ||
|
|
||
| ```bash | ||
| npx @lobu/cli@latest run # boot locally on http://localhost:{{GATEWAY_PORT}} | ||
| npx @lobu/cli@latest validate # check the config before running | ||
| npx @lobu/cli@latest login # auth the CLI (device-code flow) | ||
| npx @lobu/cli@latest apply # push this config to a Lobu org (cloud or self-host) | ||
| ``` | ||
|
|
||
| ## Conventions | ||
|
|
||
| - **Never fabricate credentials, tokens, or API keys.** Ask the user; store them in | ||
| `.env` and reference them with `secret(...)`. | ||
| - **Pause at every real decision and ask the user** — don't guess what to build. | ||
| - **`events` is append-only** — never delete rows; supersede/tombstone instead. | ||
| - **Search before create** to avoid duplicate entities. | ||
| - Run `lobu validate` after editing the config; boot with `lobu run` and verify a | ||
| real message plus the resulting memory event before calling it done. | ||
|
|
||
| @TESTING.md |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,16 +35,24 @@ const snippets = snippetsManifest as LandingSnippets; | |
|
|
||
| const EXAMPLE_BASE_URL = "https://github.com/lobu-ai/lobu/tree/main/examples"; | ||
|
|
||
| const SETUP_PROMPT = `I want to build a Lobu agent. | ||
| const SETUP_PROMPT = `I want to build a Lobu agent with you. Lobu is an open-source, event-sourced backend for AI agents: connectors emit events, memory keeps a structured knowledge graph, and agents react in real time and run on a schedule. Set it up with me end to end. | ||
|
|
||
| 1. Install the Lobu skill so you have the project conventions and tooling: | ||
| /plugin install lobu | ||
| 1. Interview me, one question at a time. Wait for my answer before the next. Don't batch them, don't guess, and don't fake any credentials: | ||
| - What is the agent for? (one sentence) | ||
| - Who uses it: just me, my team, or each of my customers (multi-tenant)? | ||
| - What should it remember? (we'll model this as 1-3 entity types) | ||
| - Where does its data come from? Lobu has built-in connectors for Slack, Gmail, GitHub, Google Calendar, Outlook, websites, RSS, Reddit, X, LinkedIn, YouTube, Hacker News, Product Hunt, and more — or you can write a custom connector for any other source (an API, a webhook, a CSV). Tell me the source and I'll map it to a built-in connector or plan a custom one. Pick one to start. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace the em dash in landing copy. Line 44 uses an em dash in user-facing text ( As per coding guidelines, " 🤖 Prompt for AI Agents |
||
| - Where do people talk to it? (Slack, Telegram, Discord, WhatsApp, web/HTTP, or MCP) | ||
| - Anything on a schedule? (optional: one watcher, e.g. a daily summary) | ||
| - Which LLM provider key do I have: Anthropic, OpenAI, or Z.ai? | ||
|
|
||
| 2. Walk me through the skill's onboarding interview (it asks what the agent should do, who uses it, where data comes from, where I'll talk to it, what should run on a schedule). Pause at every real decision and ask me, don't fake credentials, don't guess. | ||
| 2. Scaffold it: check my Node is 22-24 (Lobu rejects 25+; help me switch if not), then run npx @lobu/cli@latest init with the name and the provider from above. Postgres is built in — lobu run starts an embedded one, so don't ask me for a database unless I want an external Postgres (then I set DATABASE_URL). Read the AGENTS.md it writes (your guide to the config API: the define* helpers, connectors, auth, watchers, memory), and read examples/lobu-crm/lobu.config.ts before writing any connection, watcher, or reaction so you match the real field names instead of guessing. Then, before writing config, explain to me in plain terms how Lobu will work for my case: how the connector collects my data incrementally (feeds run on a schedule and only pull what's new since the last run — no re-ingesting), how each item becomes an event that memory turns into the entities above, and how both the watcher and the chat read that memory. Keep it short. | ||
|
|
||
| 3. Scaffold the project per my answers (lobu.config.ts plus any connector, reaction, and skill files it references), boot it locally, send a test message via the chosen channel, and show me the memory event that was written. | ||
| 3. Build it from my answers: edit lobu.config.ts plus any connector, reaction, and skill files it needs. Then tell me in one go every secret you'll need (API keys, OAuth client id/secret, bot tokens) and we'll add them to .env together as secret(...) placeholders. Never invent one, and for OAuth sources authorize the account in the admin UI rather than hand-crafting a token. | ||
|
|
||
| Lobu is an open-source event-sourced backend for AI agents: connectors emit events, memory keeps the structured record, agents react in real time and dream on cron. Repo: https://github.com/lobu-ai/lobu. Docs: https://lobu.ai/docs/`; | ||
| 4. Run and verify: run npx @lobu/cli@latest validate and fix any errors, then boot with npx @lobu/cli@latest run. Send a test message on the channel I chose, trigger the data source manually (don't wait on a poll or cron), and show me the memory event that was written plus the admin UI at http://localhost:8787. | ||
|
|
||
| Repo: https://github.com/lobu-ai/lobu. Docs: https://lobu.ai/docs/`; | ||
|
|
||
| const GITHUB_URL = "https://github.com/lobu-ai/lobu"; | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default embedded data path in docs appears incorrect.
This line says data lives under
~/.lobu/dataand referencesLOBU_DATA_DIR, but runtime behavior indicates embedded DB resolves to a root and stores cluster data at.lobu/pgdatabeneath it. Please align this sentence with actuallobu runbehavior to prevent operator confusion.🤖 Prompt for AI Agents