Skip to content

Why agents come first

Most backends were designed assuming humans write the schemas and the integration glue. dAvePi was designed assuming an AI coding agent does both. The choices that follow are different from the ones a human-first framework would make.

GET /_describe returns a compact JSON manifest of every loaded schema — fields, relations, aggregations, file fields, ACL slots, soft-delete / audit / search flags, REST endpoints, GraphQL queries and mutations, MCP tools.

An agent landing on a fresh dAvePi can plan against the API in one round-trip, before writing a line of integration code. Compare with swagger.json: 5–10× larger, Swagger 2.0 conventions, no first-class representation of relations or state machines.

→ _describe reference

Agents don’t write HTTP requests; they call tools. dAvePi’s MCP server exposes per-resource tools (list_account, create_deal, update_quote, etc.) that agents call as first-class operations.

{
"name": "create_deal",
"arguments": {
"record": { "title": "Q1", "amount": 50000 },
"idempotencyKey": "9f3c-..."
}
}

The same handlers REST and GraphQL use back the tool calls — no divergence, no maintenance tax. Both transports (HTTP + stdio) are shipped.

→ MCP server reference

Agents retry. Network blip, model timeout, harness restart. Without idempotency, retries silently create duplicate records — one of the most common agent failure modes in production.

dAvePi accepts an Idempotency-Key header on every POST, plus an idempotencyKey argument on every create_<path> MCP tool. Same key + same body = original response replayed. Different body under the same key = 409 IDEMPOTENCY_CONFLICT. Atomic claim-execute- complete protocol guards against duplicate creates under concurrent retries.

→ Idempotency keys

Every typed error the framework returns carries a structured payload: { code, message, details? }. INVALID_TRANSITION ships the current / attempted / allowed states; IDEMPOTENCY_CONFLICT ships the conflicting body’s hash; VALIDATION ships the recoverable flag. Agents read the code, not the human-readable message, and decide whether to retry.

→ Error reference

davepi gen-client walks the schema map and emits a fully-typed TS client. The same schema file that drives the server drives the agent’s frontend code at compile time. A typo in a field name is a red squiggle, not a runtime 500.

→ TypeScript client

6. A drop-in agent guide, mirrored across runtimes

Section titled “6. A drop-in agent guide, mirrored across runtimes”

Every scaffolded project ships a canonical agent.md plus three mirrors that match each runtime’s conventional path:

FilePicked up by
agent.mdCanonical, human-readable; the source of truth.
.cursorrulesCursor.
AGENTS.mdOpenAI / Codex / agentic IDEs that read this name.
.claude/skills/davepi/SKILL.mdClaude Code skills. Carries YAML frontmatter (name, description).

The guide tells the agent the conventions of the framework: don’t manually wire userId, don’t use accountId as a custom FK, prefer computed over client-side derivation, use __include rather than N+1 calls, read _describe before planning a non-trivial change. It also includes a schema field reference, a worked CRM example, prompt templates for common tasks, and the typed error catalogue.

Agents that follow it produce working code on the first try.

dAvePi is not “AI-generated code that you then maintain.” The framework is hand-written; the output of any single agent interaction is a schema file and the auto-generated surface flowing from it. There’s no LLM call at runtime. There’s no “AI-generated SQL” surface. The agent is a tool that uses dAvePi; dAvePi doesn’t use the agent.

Humans write the same schemas. The agent surfaces (MCP, _describe, the typed client) are equally useful when you’re writing code by hand — they’re not “for agents only.” But the framework’s API design optimises for the case where an agent is the primary author. Where the human-friendly choice and the agent-friendly choice diverged, we picked the agent-friendly one.