NEDB remembers the business. AiAS reasons about it. Briefprint turns it into something useful.
A person or a company answers questions once. Briefprint keeps the answers as a canonical, versioned business profile — and then generates whatever you need from it: a company profile, an investor one-pager, a VC deck outline, website copy, a bio, a demo-video script, a press release.
The interesting part is not the generation. Plenty of tools generate a deck.
The interesting part is that every sentence in that deck can be traced back to the fact that produced it, the source that fact came from, and the person or agent who recorded it — and that when the business changes, Briefprint knows exactly which deliverables just went stale.
That is a database problem before it is an AI problem, which is why the database came first.
Briefprint has exactly two hard dependencies, and both are load-bearing rather than incidental.
NEDB is the only datastore. Not a
cache in front of Postgres, and not JSON files on disk with a database bolted on
later. Business knowledge is append-only, versioned, causally linked, and needs
to answer "what did our positioning say in March, and which deck used it?" NEDB
does that natively — content-addressed nodes, AS OF time travel, typed DAG
edges, bi-temporal validity, a since() change feed, and verify() for tamper
evidence. Exports to Markdown, JSON, HTML, or PDF are artifacts. The store is
the truth.
AiAS is the only AI runtime. Briefprint contains no
provider SDKs — no OpenAI client, no Anthropic client, no Ollama calls. It talks
to one typed AiRuntime boundary, and AiAS owns provider selection, credentials,
model routing, agent execution, and retries. Swapping the model behind a
questionnaire is a configuration change in AiAS, not a code change here.
flowchart TD
U[User: CLI, SDK, or an AiAS tool call] --> B[Briefprint workflow engine]
B --> N[("NEDB<br/>knowledge · state · history · relationships")]
B --> A[["AiAS<br/>interviews · extraction · agents · generation"]]
N -.->|facts, versions, change feed| B
A -.->|structured drafts, run ids| B
B --> R[Artifacts: Markdown · JSON<br/>traceable to source facts]
Early. This repository is being built in reviewable slices, and this is the first one. Nothing is published to crates.io, npm, or PyPI yet.
What is real and tested right now:
| Component | State |
|---|---|
briefprint-core — errors, exit-code contract, canonical JSON, content-addressed ids, classification |
implemented, unit-tested |
briefprint-models — profiles, sources, claims, facts, conflicts, interviews, deliverables, artifacts |
implemented, unit-tested |
| PR CI — fmt, clippy, tests on Linux/macOS/Windows, rustdoc | implemented |
briefprint-storage — NEDB adapter, one trait over embedded + nedbd |
implemented, unit-tested + 13 live integration tests |
briefprint-aias — AiAS adapter, sentinel extraction, deterministic mock |
implemented, unit-tested + 7 live gateway tests |
briefprint-ingest, -interview, -workflow, -render, -templates, -plugins, -sdk |
not started |
briefprint CLI |
not started |
| Node and Python bindings | not started |
Crates join the workspace when they do something. A crate that compiles but does nothing is not progress, and a CLI whose subcommands print "not yet implemented" looks finished in a screenshot while helping nobody.
Three properties hold across every type in the model, and most of the codebase follows from them.
Identifiers are content-addressed. A fact's id is derived from
(profile, subject, predicate, value) — not from a random source, and not from
mutable metadata like confidence. So revising how sure you are about a claim
does not orphan the artifacts citing it, and re-ingesting an unchanged folder is a
no-op. That second property is implemented, not inherited: NEDB does not
deduplicate identical writes (a node's hash covers prev/seq/ts, so the same
payload still yields a new version), so the storage layer reads-and-compares
before writing. Measured against a live daemon rather than assumed.
Nothing is edited in place. A revised fact is a new fact that supersedes the old one. A revised answer is a new answer pointing back. This is what makes history real rather than a changelog someone has to remember to write.
Contradictions are recorded, never silently resolved. Because ids are derived from values, two live facts asserting different values for the same property are a conflict — detection falls out of the identifier scheme instead of needing a separate mechanism. "The mission changed" and "someone typed the mission wrong" look identical to a database and completely different to a founder, so Briefprint writes the conflict down and asks.
And one security property, enforced at the plugin boundary rather than by
convention: every fact carries a classification (public → internal →
confidential → restricted), every deliverable declares a clearance, and a
public landing page cannot read a confidential fact. Briefprint stores
genuinely sensitive information and exists to publish things; those two facts
together mean the boundary has to be structural.
See docs/adr/ for the reasoning in full.
Briefprint exists to be a real production consumer of NEDB and AiAS, and to find their gaps by using them properly rather than by reading their docs. Gaps found so far, all documented rather than worked around:
- No Rust client for
nedbd.nedb-engine-clientexists for Python and Node; nothing on crates.io. Briefprint needs one for its remote backend, so it ships a narrow internal client behind a trait — an upstream candidate, not a permanent reimplementation. Db::openholds an exclusive lock for the lifetime of the handle. Correct behaviour (it is the fix for a real split-brain bug), but it means an embedded CLI cannot run concurrently with itself. Hence two backends behind one trait: embedded, andnedbdover HTTP.POST /v1/databasesis not idempotent. Creating a database that already exists returns 500 with the daemon colliding against the lock it already holds itself ("locked by another process (pid …) — refusing a split-brain open"). Worked around with check-then-create. Found by running the live suite twice — the shape of bug a single run never shows.- NQL string literals have no escape syntax. The lexer scans to the next
", so a value containing a quote is unrepresentable — and a backslash-escaped attempt parses fine and matches zero rows, which reads as "no data" rather than as an error. Briefprint refuses to build such a query instead. - The HTTP put response is a minimal projection. It omits
_caused_by,_valid_from, and_valid_to, so the same call returned less over HTTP than in-process until the adapter reconciled them. - AiAS has no
response_format. Structured output must be extracted by contract, so Briefprint uses the Sentinel Blocks v1.0 format — already the convention across the ecosystem. Weaker models mangle the delimiter (llama-3.3-70bemitted<<<FACTS>>with a valid payload), so the scanner is deliberately tolerant. - The AiAS provider header is a hint, not a routing guarantee. A request sent
with
X-AiAssist-Provider: geminiwas served byclaude-fable-5, so the serving model is read from the response rather than assumed. Omitting the header is worse: an unrecognised model routed to Groq and failed naming a model never requested. - AiAS's API-key surface has no agent endpoints. Agent listing and run
cancellation live on the session-cookie plane, so agent targeting rides the
X-Agent-Idheader on chat completions and the rest is a documented gap.
BUSL-1.1 — Interchained LLC. Non-production use is granted freely: evaluation, development, testing, research, security review, and personal learning. Production, hosted, embedded, and commercial use requires written permission. Each version converts to AGPL-3.0-or-later four years after release.
Built by Mark Allen Evans Jr. (Interchained) and Vex
Lightning strikes, thunder roars, code appears. — 3 > 1
Made with HyperAgent