Files
HIPs/HIPs/hip-1111-captable.md
zeekay ad5a010f79 Three words for what a proposal is, and a generator that refuses
The same fact lived in nine hand-kept places and they disagreed about 58
proposals. This makes the file the only authority and everything else a
projection of it.

ONE VOCABULARY, in vocabulary.json, read by the lint, the generator and the
doc site. Three words, each answering "can I rely on this?" and nothing else:

    Draft    nothing implements it yet, or its own text says the work is ahead
    Final    the thing it specifies exists in the code
    Living   governance and process: amended in place, never finished

Eight spellings folded in. `Active` was the one doing real damage: on four Meta
and Process HIPs it meant living, on 48 others it meant shipped, and one word
doing two jobs is why nothing agreed. `Review` and `Last Call` described a
queue rather than a document, and a proposal under review is still one you
cannot build against.

STATUS IS EARNED, not declared. Every Standards Track proposal was checked
against the estate: 235 have their implementation, and eight do not and say so.
HIP-0095 carries a twelve-week plan ending at "mainnet launch" and has no code.
HIP-0525 specifies an all-machine meeting while apps/meet refuses a machine a
seat. HIP-0078 names a prover at a "planned location" that does not exist.
HIP-0114 is the cog.* procedure set, and that procedure set returns nothing.
HIP-0003, HIP-0102, HIP-0305 and HIP-0901 likewise: looked, found nothing.

SIXTEEN TOMBSTONES DELETED rather than statused. A dead document kept alive in
the index is one concept wearing two names. Each successor exists and carries
the text, and the 90 references that pointed at a tombstone now point at it --
whole markdown links at once, so link text cannot outlive its target. Three of
the sixteen were pure compatibility: HIP-0028 specified a migration off a
Bitnami chart, HIP-0029 dual-engine MySQL, HIP-0030 a schema-deprecation
policy. We ship no backwards compatibility, so we do not specify it.

Nine links were already broken and had been since the corpus was renumbered:
short-form ./hip-5.md paths that never existed. Two named the wrong proposal --
one cited "HIP-1: Hanzo Multimodal Models" where multimodal is HIP-0003.

THE GENERATOR REFUSES more often than it writes, because a short table looks
exactly as authoritative as a complete one. Rows must equal files; a shrinking
index must say by how much; a section whose input is missing is an error, not
an omission; nothing is written until all of it validates. Its self-test breaks
the corpus eleven ways and requires each to refuse AND leave README byte-
identical -- a guard that reports after half-writing has protected nothing.
The lint's second implementation of the same comparison is gone.

The site rendered 52 proposals with a fallback grey badge and counted them
toward none of its three stat tiles, because docs/lib/source.ts declared a
status union by hand: it admitted a `Stagnant` no file has ever carried and
omitted the one 52 files did. Five components each kept their own copy of the
colours. All six now read vocabulary.json.
2026-08-28 18:05:41 -07:00

5.2 KiB

hip, title, author, type, category, capability, status, created, requires
hip title author type category capability status created requires
1111 Captable — Who Owns What Hanzo AI Standards Track Interface captable Final 2026-08-20 HIP-0026, HIP-0106, HIP-0139

HIP-1111: Captable — Who Owns What

Abstract

/v1/captable is a company's cap table: stakeholders, share classes, share certificates and transfers, option grants and equity plans, SAFEs and convertible notes, priced rounds and their investments, and the summary that totals outstanding and fully-diluted ownership from them. It is implemented in hanzoai/cloud apps/captable. This HIP states the design worth holding to: the business logic is a ported bundle that carries no storage, the Go host is storage that carries no business logic, and each tenant's table is its own database file.

Motivation

The predecessor was a standalone application — Next.js, Prisma, Postgres — that duplicated the platform's identity, storage and deployment for one vertical. The fold retires that deployment entirely (apps/captable/captable.go:28-33): cloud's per-tenant store is authoritative from the first write, with no data to migrate and no second pod to keep honest.

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 Logic and storage are two artifacts

The cap-table logic — validation, conversion math, round mechanics — lives in a self-contained bundle, github.com/hanzoai/captable (v1.0.0 in go.mod:140), executed by the reusable goja host (apps/goja, over dop251/goja, MIT). The Go host injects exactly three primitives — __db, __newId, __now — and gives each request one SQLite transaction (apps/captable/captable.go:9-22). The bundle MUST NOT reach storage except through them, and the host MUST NOT reimplement a rule the bundle carries: one owner per concern, so the math cannot drift between two copies.

§2 The store

One SQLite file per tenant, selected by the validated org, under the host's data directory. The org selects the file AND scopes every row (apps/captable/captable.go:24-26): a cross-tenant read requires both a wrong file and a wrong predicate, which is the point of paying for two mechanisms. The per-tenant schema is seeded on first touch (apps/captable/schema.go:224).

§3 The addresses

Everything is under /v1/captable: company, stakeholders, classes, shares (and shares/transfer), plans, options, safes, convertibles, rounds (with close and investments), investments, and summary — collection and record routes composed on one group from the single prefix. Operations are typed through the registry; the wire tests (apps/captable/typed_test.go, bodyless_test.go) hold the surface to it.

§4 The in-process seam

apps/captable/facade.go lets a sibling subsystem — company formation, import and fundraising flows — write to a tenant's cap table without an HTTP hop, by dispatching the same bundle routes the handlers do. The caller MUST pass an already-validated org (apps/captable/facade.go:15-19); the facade grants no authority the HTTP path does not, it only removes the hop.

§5 Tenancy, money, events, telemetry, stage

Every route resolves the org from the validated principal (principal.Org / principal.Acting, HIP-0026), never a client header (apps/captable/captable.go:359-361); no principal, no answer. The capability is free (plugin/captable/main.go:21, cloud.Free). It publishes no events on the bus. It emits nothing to observability beyond the request span. Its stage is beta: a vertical application, not the agentic-OS core.

§6 Upstreams

dop251/goja (MIT) is embedded as the bundle interpreter, through the shared apps/goja host. hanzoai/captable is our own module, a port of the retired application's tRPC logic. Storage is the hanzoai/sqlite facade like every store in the binary. Nothing else is forked or mirrored.

Rationale

The alternative to the bundle-plus-host split is a rewrite of the cap-table math in Go. That is a second implementation of conversion and dilution rules to keep in agreement with the one that was already trusted, and cap-table math is exactly where a quiet divergence costs the most. Porting the logic whole and giving it persistence keeps one implementation; the goja host is the price, and it is shared with esign and dataroom rather than paid three times (apps/captable/captable.go:14-16).

Security Considerations

A cap table is the ownership record of a company: who holds what, at what price, under what terms. A wrong implementation leaks a competitor's round to a tenant, or worse, lets one tenant write another's ledger — a forged transfer is a forged ownership claim. Tenancy is therefore physical (a file per tenant) plus scoped (org on every row), and the org is never an input on any HTTP route. The facade is the one path that takes org as a parameter, which is why its contract requires the caller to have validated it first; a caller that passes an unvalidated org has recreated the client-supplied-header hole in-process.

References

  • HIP-0026 — Identity and Access Management
  • HIP-0106 — Hanzo Plugin Contract
  • HIP-0139 — Capability

Released under CC0 1.0 Universal Public Domain Dedication.