A dynamic, schema-driven Postgres subject store for Animus — a BaaS. This
stdio JSON-RPC subject_backend plugin lets agents declare subject kinds at
runtime (not hardcoded) and then run generic CRUD over any registered kind.
Every subject of every kind is stored in one subjects table with a JSONB
data column for the declared custom fields; the standard subject defaults
(id, title, status, priority, timestamps) are managed by the plugin.
- Runtime kind registry. Kinds live in a
subject_kindtable and are managed withsubject_kind/{declare,list,update,delete}. A kind declares a slugname, anid_prefix, an optionaltitle_field, and afieldsschema ([{name,type,required,default,description}]). - One table for all subjects.
subjects(id, kind, title, status, priority, data JSONB, created_at, updated_at). The managed columns are auto-filled; declared + ad-hoc custom fields live indata. - Validated, defaulted writes. On create the kind is resolved from the
registry, an id
<PREFIX>-<n>is minted from an atomic per-kind counter, the request's custom fields are type-checked + defaulted against the kind's schema, and managed defaults are applied. - Catch-all routing. Declares
subject_kind:*so the kernel router forwards ANY kind not claimed by another backend here (plus explicittask/requirement/blogcaps for clarity and the preflight-requiredsubject_kind:task).
Kind management (the BaaS control surface):
| Method | Shape |
|---|---|
subject_kind/declare |
{ name, id_prefix?, title_field?, fields? } → stored kind (upsert, idempotent) |
subject_kind/list |
→ { kinds: [KindDef + subject_count] } |
subject_kind/update |
{ name, fields?, title_field?, id_prefix? } → stored kind |
subject_kind/delete |
{ name, cascade? } → { name, deleted } (refuses if subjects exist unless cascade; never task/requirement) |
Generic subject CRUD over ANY registered kind, via both <kind>/<verb> and
the kind-agnostic subject/<verb> forms:
| Verb | Notes |
|---|---|
list / list_filtered |
optional status, limit, cursor |
list_prioritized |
ordered by priority desc |
next |
highest-priority ready/in-progress subject |
statistics |
counts by status |
get |
by id (task:TASK-001 or bare TASK-001) |
create |
validates + defaults custom fields; mints id |
update |
merges + re-validates custom fields, bumps updated_at |
status |
sets native status |
delete |
removes the row |
subject/{list,get,update,delete,schema,watch,unwatch} |
protocol-canonical verbs |
fields entries take a type of text, number, bool, timestamp, or
json. required: true is enforced on create only (validate-on-write):
adding a required field with no default to a kind that already has rows is
allowed — existing rows simply lack it. A declared default is filled when
the field is absent and must itself match the field type.
task(id_prefixTASK)requirement(id_prefixREQUIREMENT)blog(id_prefixBLOG, fields:authortext,slugtext,body_mdtext required,tagsjson)
knowledge is intentionally NOT seeded — the portal maps that to an existing
table separately.
- Connection URL from
DATABASE_URL(fallbackANIMUS_POSTGRES_URL). - Schema (
subject_kind+subjects, with indexes on(kind, status)and a GIN index ondata) is auto-created on startup unlessANIMUS_POSTGRES_AUTO_MIGRATEis falsey. - Back-compat: when a prior hardcoded-layout
taskstable exists, itsTASK-*/REQUIREMENT-*rows are migrated intosubjects(ids, status, priority, and the full legacyjsonpayload preserved underdata, timestamps from the legacy metadata). The import guards on table existence and usesON CONFLICT (id) DO NOTHING, so it is safe + idempotent.
animus plugin install launchapp-dev/animus-subject-postgresProvide a Postgres URL via the environment (DATABASE_URL or
ANIMUS_POSTGRES_URL) before starting the daemon.
| Env var | Default | Description |
|---|---|---|
DATABASE_URL |
— | Postgres connection URL |
ANIMUS_POSTGRES_URL |
— | Fallback Postgres URL when DATABASE_URL is unset |
ANIMUS_POSTGRES_AUTO_MIGRATE |
on | Set to 0/false/no/off to skip auto-migrate |
ANIMUS_DEFAULT_TASK_ID_PAD |
3 |
Zero-pad width (e.g. 3 → TASK-007) |
cargo build --release
cargo test # pure-logic unit tests
DATABASE_URL=postgres://localhost/animus_test cargo test -- --ignoredElastic License 2.0. See LICENSE.