1CHANNELS
16TABLES
D0–D3GATES
ALL GATES ARMED
--:--:--
中文
G1–G5 · operations agent shipped

Run growth as one
decision-gated personal agent

Research, customer mining, CRM, email outreach and demand/supply matching as one operations personal agent. Research is read-only by default and runs offline without a key; email outreach is gated by the zeus kernel and nothing is ever sent without human sign-off. Signals are scored and deduplicated, every lead and match is traceable, and nothing unbuilt ever fakes success.

1 operations agent84 tests green16 tables
OPERATIONS CONSOLE1 SEARCH CHANNEL · TAVILY
ZEUS DECISION KERNEL · HTTPoutbound is graded here, never locally
D2 email  HELD 423 → APPROVED → mail.send
D3 batch   HELD 423 → APPROVED → mail.send
kernel down  503 DECISION_UNAVAILABLE · fail-closed
MAIL / SEARCH PORTSSMTP and Tavily, both behind ports
tavily search  ONLINE · real search with key
smtp mail      FAIL-CLOSED · off mode 503
AUDIT LEDGER · lead_events + outreach_eventsevery key action, replayable
lead.promoted  source=signal score=89 idempotent=hit
draft.sent      decision=D2 messageId=msg_1
match.created    score=90 reasons=category+price
signal / lead flowdecision gate · zeusmail / search portclosed loopfail-closedstatic ops console diagram
the closed loop

How one growth lead travels the whole loop

Five stations from market research to a matched buyer/supplier pair. Search and mail sit behind ports, and the one external action — email outreach — pauses at a zeus decision gate until a human approves. Nothing jumps the gate.

  1. 01
    PRODUCT

    Research

    A read-only SearchProvider gathers mentions, normalizes, deduplicates by fingerprint and scores them with a deterministic local scorer — no model, no key required for the offline loop.

  2. 02
    CONTENT

    Insight

    Need, pain and comparison signals cluster into demand insights that stay pending_review until a human confirms or rejects them.

  3. 03D3 GATE
    LISTING

    Lead mined

    High-intent signals promote into leads idempotently, inherit their score and evidence, and move through a validated new→qualified→contacted→won/lost state machine with a follow-up watch.

  4. 04
    ORDER

    Outreach gated

    A draft goes to zeus for a D2 decision and returns held. The SMTP mail port fires only after human approval — no sign-off, zero outbound.

  5. 05D2 GATE
    REFUND

    Match scored

    Buyer demands and supplier offers are matched across category, quantity, price, deadline and region into an explainable 0–100 score, then routed into a contact draft for outreach.

domain modules

One codebase, nine focused modules

Each module owns one part of the growth loop and talks to the rest through explicit ports. Search, mail and decision are contracts, so a new search provider, another mail channel or the zeus kernel all plug in without rewriting the domain.

RESEARCH

Research engine

A SearchProvider port with an offline deterministic provider and an online Tavily provider; signals are deduplicated, scored and clustered into reports with evidence URLs.

CRM

Customer & leads

Contacts, leads, a validated state machine, follow-up timeline and a watch for due re-engagement — every transition lands in lead_events.

OUTREACH

Email outreach

Campaigns and drafts with a submit→zeus→approve→send flow. Bounces suppress, replies reflow into follow-ups, and open tracking is off by default.

MATCH

Matching engine

Buyer demands × supplier offers scored across five dimensions into an explainable match, with an introduction builder that feeds outreach.

DECISION

Decision port

A DecisionPort hands outbound actions to zeus over HTTP via zeus-client. There is no local grading; an unreachable zeus returns 503.

MAIL

Mail port

A MailPort with an SMTP adapter (STARTTLS or implicit TLS). Off mode fails closed; smtp without host/from returns 422.

STRUCTURER

Signal structurer

Classifies a signal as buyer demand or supplier offer and extracts category, quantity, price, MOQ, region and email with rules — never hard-filling a missing field.

MATCHER

Score matcher

A pure five-dimension scorer (category 40 / quantity 20 / price 20 / deadline 10 / region 10) with per-dimension reasons.

STORAGE

Dual-dialect storage

SQLite locally and PostgreSQL in production; six paired migrations across sixteen tables, enforced by check:migrations.

engineering guarantees

Designed to fail-closed, not to fail-open

Growth OS reaches real people by email and touches real market data. It would rather refuse and return a precise error than perform something it cannot authorize. These four guarantees are enforced by the code and its tests.

FAIL-CLOSED1

Fail-closed by default

Missing search credentials return 422 CREDENTIAL_MISSING; an unreachable zeus returns 503 DECISION_UNAVAILABLE; mail in off mode returns 503. No outbound ever happens without authorization.

DECISION EXTERNALIZED2

Grading is externalized to zeus

The repo never grades locally. Every outbound email goes to the decision kernel over HTTP — single send D2, batch or high-impact D3 — and waits for human approval.

NO FAKE SUCCESS3

No fake success

Offline search is an explicitly labeled replay, never a silent stand-in for a real provider; and no sign-off means zero outbound, verified by a strong negative test.

IDEMPOTENT & AUDITED4

Idempotent & audited

Signals deduplicate by fingerprint, lead promotion is idempotent, and lead_events plus outreach_events record every transition and send, matching zeus decision records one to one.

architecture

Ports-oriented layering; dialect lives only in storage

HTTP v1 routes, a composition root, domain modules and three ports. Storage speaks both SQLite and PostgreSQL, with dialect confined to the storage layer and paired, numbered migrations.

L1

Runtime & quality gates

Node ≥22, TypeScript strict (noUncheckedIndexedAccess, exactOptionalPropertyTypes), 84 Vitest cases across 14 files with the G1–G5 gates.

L2

Dual-dialect storage

Bundled node:sqlite locally with zero dependencies, PostgreSQL in production; sqlite/pg migrations are paired by number and enforced by check:migrations.

L3

Three ports

SearchProvider (offline/online), DecisionPort (zeus-client), MailPort (SMTP).

L4

Domain modules

research · crm · outreach · match · decision · mail · structurer · matcher · storage.

L5

Composition root · serve.ts

Loads .env, injects the search provider, DecisionPort and MailPort at assembly; domain modules depend only on ports.

L6

HTTP v1 · Hono

Research, CRM, outreach and match routes with one unified error envelope { error: { code, message, retryable, details? } }.

DEPLOY
open source · self-host

Spin the whole agent up on your machine in minutes

No live credentials required: offline search replays recorded fixtures, a fake-zeus decision path and the G1–G5 test suites prove the loop, and SQLite is the default with PostgreSQL ready for production.

  • 84 tests green across research, CRM, outreach and matching, including the no-sign-off-zero-outbound negative proof.
  • SQLite by default via bundled node:sqlite; PostgreSQL for production, with six paired dual-dialect migrations.
  • Offline search replays recordings — no network, no key. Wire GROWTH_SEARCH_API_KEY (Tavily) to switch to real search.
  • Mail and zeus stay fail-closed until you wire them — SMTP and the decision kernel are opt-in, never faking success.
QUICKSTART:8787
# clone + install
$ git clone https://github.com/bayernjf/growth-os.git growth-os
$ cd growth-os && npm install
# migrate the local SQLite store
$ npm run migrate:up
# start — http://127.0.0.1:8787
$ npm start

G1–G5 milestone artifact. Live search needs a Tavily key; email needs SMTP and a running zeus.