Agent playbooks

A playbook holds what your AI agents should say and do, approved by a person:

Agent playbooks

A playbook holds what your AI agents should say and do, approved by a person:

  • FAQs: a question and its approved answer.
  • Skills: named markdown instructions for a task (how to issue a refund, how to escalate an outage), loaded by an agent only when the task needs them.

Agents discover both by meaning: they send a task or a user's question in their own words and get back the published FAQs and skills that fit. Every edit makes a new version, and agents only ever see the version a person published.

Agents, and the agent memory store you link, propose new FAQs with the evidence they rest on. The proposals wait in an inbox until an admin or owner accepts, edits or rejects them. Link a semantic cache and every published answer is also put there, so your application's cache lookup serves the approved text without asking a language model.

Agent playbooks are part of Kivi Synapse.

How it works

A playbook lives in one of your databases. Its settings (name, embedding model, links) are kept by KiviDB Cloud; everything written to it is stored in that database, under keys starting kividb:pb:{<playbook id>}::

KeyHolds
e:faq:<id>, e:skill:<name>the entry: state, newest version, published version, who changed it and when
v:faq:<id>, v:skill:<name>its versions, newest 20 and the published one
x:pub:faq:<id>, x:pub:skill:<name>the published version, with its embedding: what discovery searches
x:ent:<id>the newest version of each FAQ that is not archived, for duplicate checks
x:prop:<id>one pending proposal, with its evidence
faqs, skills, proposalssorted sets for listing and the limits
metacounts of accepted, rejected and dropped proposals

and one search index, kividb:pb:<playbook id>:idx, over the x: keys. A published document exists only while its entry is published, so a draft or an archived entry cannot be discovered.

States and versions

StateAgents see it
draftno: written, never published
publishedyes, the published version (an edit after publishing is a new version agents do not see until it is published)
archivedno; its versions are kept, and publishing it again brings it back

Each save is a new version, numbered from 1. Publish any kept version to roll back to it. The newest 20 versions are kept, plus the published one; an older version is removed when a new one is saved.

Who may do what

ViewerMemberAdmin, owner
See the playbook's settings and countsyesyesyes
Read FAQs, skills and proposals; discovernoyesyes
Write drafts, save versions, proposenoyesyes
Publish, archive, delete, review proposals, change settingsnonoyes

API keys carry the same roles. When the organization's audit log is on, settings changes, publishing, archiving, deleting and every review are recorded.

Embeddings

Discovery and duplicate checks compare embeddings. A playbook uses one of:

embed_provider
local (default)all-MiniLM-L6-v2, run inside KiviDB Cloud, 384 dimensions. Nothing leaves KiviDB and there is no extra charge.
kividbour hosted embedding model (256, 512 or 1024 dimensions), billed per token as described in hosted models.
openaiOpenAI with your key, e.g. text-embedding-3-small
openai_compatibleany HTTPS endpoint with OpenAI's /embeddings shape, with your key

Keys are stored encrypted and never returned. An endpoint's address is checked when saved and on every call, and private and internal addresses are refused. The model and size can change only while the playbook is empty.

API

Every call takes an API key (Authorization: Bearer kvdb_...) or a console session, and names the database and the playbook: /instances/{database_id}/playbooks/{playbook}.

Create a playbook

curl -X PUT https://api.kividb.io/instances/$DB/playbooks/support \
  -H "Authorization: Bearer $KIVIDB_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "description": "Approved answers for the support assistant",
    "embed_provider": "local",
    "memory_store": "support-memory",
    "cache_namespace": "support-answers",
    "proposal_interval_minutes": 60,
    "dedupe_threshold": 0.9
  }'

memory_store and cache_namespace are optional and must be in the same database. GET the same path for its settings and counts, DELETE it to remove the playbook and everything it stored (including its answers in the linked cache). GET /playbooks lists every playbook in the organization.

FAQs

# A draft, version 1
curl -X POST https://api.kividb.io/instances/$DB/playbooks/support/faqs \
  -H "Authorization: Bearer $KIVIDB_API_KEY" -H "Content-Type: application/json" \
  -d '{"question": "How long does a refund take?",
       "answer": "Refunds reach the original card within 5 business days of approval.",
       "tags": ["billing"]}'
# {"faq": {"id": "3f9c1a0b7d2e4c51", "version": 1}, "state": "draft"}

# Publish it (admin or owner). Without "version", the newest is published.
curl -X POST https://api.kividb.io/instances/$DB/playbooks/support/faqs/3f9c1a0b7d2e4c51/publish \
  -H "Authorization: Bearer $KIVIDB_API_KEY" -H "Content-Type: application/json" -d '{}'
# {"published_version": 1, "previous_version": null, "cache": {"namespace": "support-answers", "ok": true, ...}}
CallDoes
GET …/faqs?offset=&state=a page of 50, most recently changed first
POST …/faqsa new draft {question, answer, tags?, note?}
GET …/faqs/{id}the entry and every version kept
PUT …/faqs/{id}a new version, same body as POST
POST …/faqs/{id}/publish{version?}: what agents see
POST …/faqs/{id}/archivehide it from agents (and remove it from the linked cache)
DELETE …/faqs/{id}delete it and its versions

Skills

curl -X POST https://api.kividb.io/instances/$DB/playbooks/support/skills \
  -H "Authorization: Bearer $KIVIDB_API_KEY" -H "Content-Type: application/json" \
  -d '{"name": "issue-refund",
       "description": "Step by step: check eligibility, issue the refund, tell the customer.",
       "body": "# Issue a refund\n\n1. Check the order is under 30 days old.\n2. Refund it in Billing > Orders.\n3. Reply with the refund id.",
       "tags": ["billing"]}'

A skill's name is 1-64 lowercase letters, digits, - or _, starting with a letter, and cannot change. Its body is markdown, up to 64 KB. The calls are the FAQ ones under …/skills/{name}, except:

CallDoes
GET …/skills/{name}the published skill, whole: what an agent loads
GET …/skills/{name}/versionsthe entry and every version kept

Skills are written or pasted as markdown; uploading a ZIP package is not supported.

Discover

curl -X POST https://api.kividb.io/instances/$DB/playbooks/support/discover \
  -H "Authorization: Bearer $KIVIDB_API_KEY" -H "Content-Type: application/json" \
  -d '{"task": "when will I get my money back?", "kinds": ["faq", "skill"], "top_k": 5, "min_score": 0.4}'
{
  "results": [
    { "kind": "faq", "id": "3f9c1a0b7d2e4c51", "question": "How long does a refund take?",
      "answer": "Refunds reach the original card within 5 business days of approval.",
      "tags": ["billing"], "version": 1, "score": 0.8123 },
    { "kind": "skill", "name": "issue-refund",
      "description": "Step by step: check eligibility, issue the refund, tell the customer.",
      "tags": ["billing"], "version": 2, "score": 0.6011 }
  ],
  "latency_ms": 14
}

kinds defaults to both, top_k to 5 (at most 20). score is cosine similarity, 0 to 1. Only published versions are returned. For a skill, load the body with GET …/skills/{name} when the agent decides it needs it.

Proposals

curl -X POST https://api.kividb.io/instances/$DB/playbooks/support/proposals \
  -H "Authorization: Bearer $KIVIDB_API_KEY" -H "Content-Type: application/json" \
  -d '{"question": "Can I change the delivery address after ordering?",
       "answer": "Yes, until the parcel ships: Orders > Change address.",
       "evidence": [{"source": "ticket 4471", "excerpt": "Changed the address before dispatch, customer confirmed."}],
       "proposed_by": "support-bot"}'
# {"accepted": true, "proposal_id": "a1b2c3d4e5f60718"}

Evidence is required: one to ten {source, excerpt} items. A proposal at least dedupe_threshold similar (default 0.9) to an FAQ that is not archived, or to a pending proposal, is not added; the reply names the one it repeats:

{ "accepted": false, "duplicate_of": { "kind": "faq", "id": "3f9c1a0b7d2e4c51", "question": "How long does a refund take?", "score": 0.97 } }
CallDoes
GET …/proposals?offset=the inbox, newest first, and dropped: how many the limit has removed
POST …/proposals/{id}/accept{question?, answer?, tags?, publish?}: make an FAQ from it, with your edits; publish: true publishes it at once
POST …/proposals/{id}/rejectremove it

An accepted FAQ's first version notes who proposed it and its evidence sources.

Proposals from agent memory

Link an agent memory store in the same database and, every proposal_interval_minutes (15 to 1,440, default 60), KiviDB reads the long-term memories and session summaries the store has added since the last read (up to 50 memories and 20 sessions a run) and asks the store's own language model for FAQ candidates. Each candidate must cite the memories or summaries it rests on; those become its evidence, and one that cites nothing it was given is dropped. At most five are proposed a run, and the duplicate check above applies.

  • A store without a language model proposes nothing; the console says so.
  • A newly linked store is read from its oldest memory onward, a batch a run, and each memory is read once.
  • If the model fails, the same material is tried again next run; after five failed runs it is skipped and the playbook shows that it was.
  • Read memory now in the console's inbox (or POST …/run, admin or owner) runs it at once.

Model calls use the store's settings: our hosted model, billed per token, or your provider with your key.

The approved-answer loop

Link a semantic cache namespace in the same database and:

  • publishing an FAQ puts its question and answer in the cache, embedded by the namespace's own provider so lookups compare like with like;
  • publishing a new version replaces that entry; archiving or deleting the FAQ removes it;
  • entries are put with a year's expiry and refreshed daily, so an answer stays cached while it stays published;
  • linking a namespace puts every published FAQ in it; unlinking takes them out.

A namespace without a provider (none) is given the playbook's own embedding of the question, so it must have the playbook's size, and your lookups must use the same model (all-MiniLM-L6-v2 for local). Cached entries carry {"source": "agent_playbook", "playbook": …, "faq_id": …, "version": …} as metadata. If a put fails, the publish still stands; the console shows the error and the daily refresh tries again.

From an AI assistant

The KiviDB MCP server has list_playbooks, playbook_discover, playbook_get_skill and playbook_propose. A typical agent loop: call playbook_discover with the user's question; answer from a returned FAQ, or load a returned skill with playbook_get_skill and follow it; when it learns something that should be an FAQ, call playbook_propose with the evidence. Playbooks are created and entries published in the console or over the API.

Limits

Playbooks20 per database
FAQs2,000 per playbook (archived ones count; delete them to make room)
Skills200 per playbook, each up to 64 KB of markdown
Versions keptthe newest 20 per entry, and the published one
Pending proposals500 per playbook; past that the oldest are dropped and counted
Question / answer500 / 8,000 characters
Evidence1 to 10 items per proposal, each excerpt up to 2,000 characters
Discovertop_k up to 20

Not available on sharded databases yet. It uses the database's own memory, with no extra charge beyond the database.