Skip to content

Company document branding and invoicing ​

Company OS has one resolved document profile per company. It is the source of truth for branded letters, invoices, reimbursement lines, and invoice-related agent work.

Resolution ​

Every company starts with an adapted copy of the platform default:

config/company-os-document-brand-profile.v1.json

The baseline is the Gestion Velora system used for the SDC Enticy invoices: bilingual French/English labels, CAD, Letter portrait layout, the Gestion Velora wordmark and contact block, GST 5%, QST 9.975%, Net 30, 2% monthly late fees, $60/hour after-hours work with a three-hour minimum, and explicit reimbursement lines. Company OS keeps those structural rules while replacing the identity with the company's known name and supplied branding. If company identity is unavailable, the unadapted platform profile remains the fallback.

Passport setup choice ​

When a new company is created, Passport asks the operator to choose one starting point:

  1. Use the adapted Gestion Velora baseline (recommended). Company OS keeps the invoice structure and replaces the identity with the company's supplied display name, optional legal name, invoice name, billing contact, and website.
  2. Share an existing invoice or template. The file is uploaded through the existing Passport evidence endpoint and remains non-authoritative reference evidence while it is reviewed.
  3. Describe a preferred format. The notes are stored as a pending request for an authorized profile change.

The first option is ready immediately. The second and third options do not silently change the active profile; an authorized person must approve a complete governed profile override before the requested format becomes active.

If a company supplies another approved invoice format, store a complete adapted profile as a governed company override. The override is stored under company_profiles.metadata.document_brand_profile; unrelated company metadata is preserved. The active profile is returned by:

GET /api/company/companies/{company_id}/document-profile

The same resolved profile is injected into GET /api/company/tasks/{task_id}/llm-context as document_profile and as the document_profile context section. Agents therefore see the active format without relying on a chat instruction or a local file guess.

CLI ​

Read the active profile:

bash
company-os company profile show
company-os company invoice-format show

Create a company override from a JSON file. The file must use the versioned company_os.document_brand_profile.v1 schema and contain brand and invoice_format objects:

bash
company-os company profile set --file PROFILE.json --dry-run
company-os company profile set --file PROFILE.json --confirm

For an invoice-only adaptation, the CLI preserves the current brand and accepts either a full profile, an object containing invoice_format, or a standalone company_os.invoice_format.v1 object:

bash
company-os company invoice-format set --file INVOICE_FORMAT.json --dry-run
company-os company invoice-format set --file INVOICE_FORMAT.json --confirm

--dry-run performs the read and validation path, then returns the planned governed PUT without writing. Mutations still require the existing Company OS principal, policy scope, confirmation, governance receipt, and independent readback controls.

The CLI accepts the endpoint response itself as an input file, so an operator can run company profile show > PROFILE.json, edit it, and submit it again. Do not put credentials, tokens, passwords, or other secrets in a document profile; the server rejects those field names.

Rendering branded PDFs ​

Invoices and board minutes render to PDF from the resolved profile with pdfcn components on the Forme (WASM) engine, in web/company-console. The source record's schema selects the document:

bash
company-os company profile show > PROFILE.json
npm --prefix web/company-console run render:company-document -- \
  --profile PROFILE.json --source RECORD.json --out document.pdf [--logo logo.png]

Every PDF prints short SHA-256 digests of the profile and the source record (canonical JSON), and the command prints the full digests, as the pack's document-governance policy requires. When something is missing, the document shows a visible review box instead of a guessed value.

Invoices — company_os.invoice_document.v1 ​

Sample: web/company-console/scripts/fixtures/company-invoice.sample.json. Lines are service, after_hours (billed at the profile rate with its minimum hours), or reimbursement. GST and QST are computed on the same pre-tax base and the due date comes from the NET n label. Review items: a reimbursement without a receipt, tax registration numbers absent from the profile, a line marked tax-exempt. Drafts carry a BROUILLON · DRAFT watermark.

Board minutes (procès-verbal) — company_os.board_minutes_document.v1 ​

Sample: web/company-console/scripts/fixtures/company-board-minutes.sample.json. Follows the board-minutes handbook:

  • resolutions keep their status (adopted, proposed, rejected, deferred) with mover, seconder, vote, and source_ref;
  • quorum is counted from attendees (present and proxy); a stated count that disagrees, an unstated requirement, or a missed quorum is flagged;
  • the action ledger prints a missing owner or due date as Inconnu · Unknown and flags it;
  • unresolved items (legal interpretation, missing evidence, …) get their own section; decisions or commitments without a listed source are flagged;
  • status: "adopted" requires adoption.date and adoption.reference. Drafts state that they are not adopted and that distribution needs explicit approval; adoption never implies distribution approval;
  • confidential: true marks the masthead and every footer.

Fonts ​

The profile's brand.typography chooses the families: family (both roles), or body_family and display_family, plus an optional title_weight (a title_style containing "light" means 300). A profile without typography uses the Gestion Velora baseline, Calibri. Invoices alone can use other families through invoice_format.typography (same keys); the procès-verbal and other documents always use brand.typography. Gestion Velora Inc. sets Liberation Mono / Liberation Sans there, the typefaces of its invoices. Set it in the company's own profile, not in the platform baseline: the server copies invoice_format into every company it adapts. Try other families without editing the profile with --body-font and --display-font.

Families resolve through the font library, in order: bundled (public/fonts/pdf/), Vercel (Geist, Geist Mono), fonts installed on the computer (Microsoft Office, LibreOffice, user and system fonts — read in place, never copied into the repository), then 67 curated Google Fonts downloaded once into ~/.cache/company-os/fonts. A family available nowhere falls back to its metric-compatible open substitute (Calibri → Carlito, Cambria → Caladea, Arial/Helvetica → Arimo, Times → Tinos, Courier/Liberation Mono → Cousine, Georgia → Gelasio), then to Inter. The render summary reports the family actually embedded and any substitution, so a document rendered on a machine without Office says so.

bash
npm --prefix web/company-console run fonts -- list [--category sans|serif|mono|display] [--origin system]
npm --prefix web/company-console run fonts -- install --all     # cache Google Fonts for offline use
npm --prefix web/company-console run fonts -- specimen --out fonts.pdf

Only fonts that draw Latin text with French accents are listed, and only TrueType-flavoured files: Forme silently replaces woff2 and CFF .otf fonts.

Code layout ​

Blocks live in components/pdf/blocks/company-invoice/, company-board-minutes/, and company-shared/; models in lib/company-documents/; the profile-to-theme mapping in lib/pdf-themes/company-profile.ts. Brand fonts (Inter, Playfair Display, OFL) are in public/fonts/pdf/. The other files under components/pdf/, lib/, and types/ are pdfcn registry copies — update them with npx shadcn add @pdfcn/forme/<item> --overwrite, not by hand. Tests: npm --prefix web/company-console run test:company-documents.

Company OS documentation — built with VitePress