Skip to content

Box architecture boundaries

These boundaries are load-bearing. Do not cross them without an explicit, written product/security decision.

  1. Box has no UI of its own. Box exposes a Cafaye-only JSON API. It must never gain a frontend, admin console, or any other human UI. The frontend is cafaye/website (parlor-derived, one frontend for the whole stack), and operational visibility belongs there.

    Amended 2026-10-09 (user decision): the single UI is website, not parlor. Box’s UI stays somebody else’s problem either way.

    Amended 2026-10-15 (owner decision, settled): cafaye/box is re-scoped from “the installer web UI” to “the console” — the human surface of the control plane. The console surface above stands: the single frontend remains cafaye/website, and Box still grows no UI of its own. What changes is what this API owes its clients: one control plane, two clients. The cafe CLI is primary (the agent’s hands); the Box console is the human’s eyes (trust, visibility, onboarding). The console is a client of this same API — same auth, same tenancy, same billing service, no separate logic — so from now on the API must serve both clients identically: a console-only capability or a CLI-only capability is a boundary violation. (“If CLI can do it, Box can show it. If Box can do it, CLI can do it.”)

  2. Box is Cafaye-only. It runs on Cafaye infrastructure. It is never part of customer source bundles, customer installs, or the Kit deployment substrate, and no Box code may assume otherwise.

  3. Customer services stay where they are. Identity, Gateway, Courier, Parlor, and Kit remain the customer data plane. Box coordinates from the outside; it does not absorb them.

  4. The customer’s own app repo stays their source of truth. Box records Cafaye-side coordination state (entitlements, installations, releases, update decisions). It never rewrites customer source.

  5. No release is auto-applied without customer acceptance. Any release or update workflow must gate on an explicit customer acceptance step — in the browser, or a scoped, expiring approval token bound to that one release. A “convenient” auto-apply is a defect, not a feature.

  6. Box holds no readable customer secret. (added 2026-10-09) Provider credentials are stored as envelopes sealed to a box’s public key: Box persists ciphertext it cannot open. A test asserts no plaintext provider secret reaches its database. The same rule applies to any future secret-shaped value — Box is a courier, never a vault.

    The public half arrives at enrollment: the box reports public_key in its box.enroll redemption (cafaye/cafe/internal/box/control_plane.go) and Box writes it to the installation the capability minted, so the capability that bought the enrollment binds the key every later signature is verified against and every later envelope is sealed to. Only the public half is ever accepted — private key material in that field is refused, and a refusal does not spend the capability.

    Registry material, and where it lives — added 2026-10-13, by the registry-capability-exchange packet. A registry.pull capability is redeemed at this door and answers a receipt: the scope, never a credential. Box does not mint the dockerconfigjson that receipt is traded for, and the material a mint would need (a GitHub App private key scoped to read:packages) is secret-shaped — so boundary 6 above (“Box is a courier, never a vault”) and the guardrail below (“No GitHub App integration”) refuse it here twice over. That trade lives in cafaye/registry, a standalone service that spends the capability at this door and hands the credential back over the response body, which makes the fleet’s one registry credential a one-process question instead of a control-plane feature. Box still holds nothing it could not publish. A change tempted to serve the credential from a route here should read cafaye/registry/README.md first: the option argument, including why this would not be a simplification.

  7. Agent identity lives in Identity, not here. (added 2026-10-09) The agent principal, its claim state and its tokens are Identity’s — Identity is the fleet’s auth authority (Box forwards its bearer there and verifies nothing itself). Box holds installations, entitlements, releases, approvals and the audit trail of what an agent did, and mints box-scoped capabilities; it never becomes a second identity provider, token store or user directory.

  8. Box access is not the control plane’s. (added 2026-10-09) Box may record installation state, mint short-lived enrollment capabilities bound to a specific box, and receive outbound mTLS reports from that box. It holds no SSH key, no box credential and no root — a capability it issues is redeemed on the box, not by the control plane.

    The client certificate — added 2026-10-13, by the Phase C box-certificate packet. Enrollment also issues the box a client certificate to present on the mTLS channel (BoxCertificate). This is not the box credential this boundary forbids Box to hold: the certificate is public, its authority is exactly “this is box X talking to the control plane” (ExtKeyUsage clientAuth, CA:FALSE, CN = box_id), and Box stores no private key — issuance hands the key back once and keeps only the certificate and its fingerprint. The daemon, not Box, holds the key; the certificate is rotatable and revoked by re-issuance.

  • No frontend, assets, or Madmin. The UI is cafaye/website.
  • No billing/Stripe integration, and no payment webhooks. We sell, but the mechanism is Stripe Payment Links plus manual reconciliation: a human confirms payment and grants the entitlement through the existing operator endpoints. Box never talks to a payment processor. When a real billing service exists, revisit this line deliberately rather than growing into it.
  • No GitHub App integration.
  • No customer-stack code, no SSH key, no box credential. Recording installation state and issuing capabilities is in scope (boundary 8); reaching into a box is not.
  • No speculative product endpoints: each new endpoint needs the workflow it serves to exist first.
  • No secrets. Boundary 6 governs this repo’s data at rest.
  • Probes (/healthz, /readyz) must stay minimal and must never expose configuration, secrets, or internal dependency details.
  • Entitlements are granted explicitly, never implicitly. They are granted either by staff through the operator endpoints, by a human confirming a reconciled payment, or by an explicit claim step — and never by an agent acting alone, and never with automatic updates. There are no prices, plans or payment webhooks here. Staff identity is always re-checked against Identity per request; Box holds no local user/password store and no JWT verification of its own.
  • There is no automatic-update path. Boundary 5 covers every rollout, including the ones an agent proposes.

Recorded rather than silently edited, because the original text said the opposite. The agents-first product (moon/AGENTS-FIRST.md) needs Box to carry installations, releases, approvals and capability minting, and to sit behind a website UI — so boundaries 1, 4 and two guardrails changed shape on 2026-10-09 by explicit user decision. What did not move and still does not apply to this repo: UI ownership, box access, payment integration, secrets, and auto-apply.