Orbit

In development

A CRM for one revenue team that turns customer activity reported by the tools they already run into explainable, human-reviewed next actions.

Orbit is in development. It has no public source release or install path yet, and no date. This page shows the requirements and documents its publisher has released so far.

Category
Sales
Licence
MIT
Version
0.1.0
Requirements
64 clauses
Publisher’s stage
complete-workflow-implementation; acceptance requires pinned runtime and native receipts

Screenshots

From the project’s own visual and verification records. Its handover says what was exercised.

Orbit screenshot 1: verification ui 1440 app notifications
Orbit screenshot 2: verification ui 1440 app records
Orbit screenshot 3: verification ui 1440 app settings
Orbit screenshot 4: verification ui 1440 app sources
Orbit screenshot 5: verification ui 1440 app
Orbit screenshot 6: verification ui 1440 assistance preview

Outside services

The services the project declares it sends data to, each with its reason.

sendgrid
Native sign-in and operator-approved mail require an external delivery provider.
openai
Generate operator-requested recommendation explanations and drafts from the exact reviewed preview.

Scope and limits

What it will not do

  • A second workspace
  • Roles, territories, or private records
  • A second pipeline
  • Workflow builder
  • Bulk campaigns or sequences
  • Autonomous customer outreach
  • SMS, phone, or social sending
  • Attachments on outbound messages
  • Email or digest notifications
  • A tracking script, cross-site tracking, fingerprinting, or data-broker identity resolution
  • Hosted forms or landing-page building
  • Marketing CMS, ads, or multi-touch attribution
  • Per-record currencies
  • Plan or pricing pages
  • Revenue forecasting
  • Subscription billing or plan enforcement
  • Native mobile applications

Extension points

Optional conveniences for common changes. Owners can change any source, including core logic, schema and infrastructure.

  • signal.sources.v1
  • operator.management.v1
  • record.identity.v1
  • opportunity.assignment.v1
  • opportunity.scoring.v1
  • opportunity.prioritization.v1
  • opportunity.next-action.v1
  • outreach.instructions.v1
  • outreach.quiet-hours.v1
  • signal.recorded.v1
  • record.merged.v1
  • opportunity.evaluated.v1
  • opportunity.queue-changed.v1
  • recommendation.created.v1
  • outreach.scheduled.v1
  • outreach.accepted.v1
  • outreach.failed.v1
  • notification.created.v1
  • navigation.after.v1
  • now.header.after.v1
  • now.row.actions.v1
  • contact.sidebar.after.v1
  • company.sidebar.after.v1
  • opportunity.header.after.v1
  • opportunity.sidebar.after.v1
  • opportunity.timeline.after.v1
  • composer.context.after.v1
  • settings.sections.after.v1
  • mail.sender.v1
  • ai.provider.v1

Declared limits

Status
estimated-until-load-tested
Operators
25
Contacts
100,000
Companies
25,000
Open Opportunities
25,000
Signals
1,000,000
Timeline Activities
2,000,000
Signal Payload Bytes
262,144
Signed Ingress Requests Per Minute
600
Public Requests Per Minute Per Ip
300
Outbound Messages Per Minute
3
Outbound Messages Per Operator Per Rolling Day
100

Requirements

All 64 clauses of Orbit’s CONTRACT.md. They say what the project must do; the handover and verification records say what is built and tested.

TEAM 4 clauses

  1. TEAM-001
    Equal operators. Every operator can view and act on every contact, company, opportunity, signal, activity, and notification. There are no roles and no private records.
  2. TEAM-002
    Management. Operators are invited and removed in settings. The operator configured at setup can be removed only by themselves. Policy: operator.management.v1; default: any operator may invite or remove.
  3. TEAM-003
    One workspace. A deployment holds exactly one workspace and offers no way to create a second. Its name, timezone, currency, working hours, stale interval, awaiting-response interval, pipeline stages, signal sources, and free-mail domain list are configured in settings and apply to every record.
  4. TEAM-004
    Removal handover. Removing an operator revokes their sessions, cancels their scheduled messages, and unassigns their open opportunities. Their notes, drafts, sent messages, and timeline entries remain and stay attributed to them.

RECORD 13 clauses

  1. RECORD-001
    Core records. Operators can create, edit, and delete contacts, companies, and opportunities. A contact requires a name or an email address and may also hold a phone number, job title, and timezone; a company requires a name and may hold one primary domain; an opportunity requires a title and holds a pipeline stage, a value in the workspace currency, zero or one owner, an expected close date, at most one company, and any number of contacts. Each entity listed in seed.json → customFieldEntities also holds custom fields.
  2. RECORD-002
    Associations. A contact belongs to at most one company and to any number of opportunities. An opportunity with at least one contact names one of them primary, and that contact is the default recipient for its outreach; an opportunity with no contact is never recommended an email follow-up. Changing an association moves no timeline entry: each record keeps the entries it already had.
  3. RECORD-003
    Identity keys. A contact's key is its email address lowercased with surrounding whitespace removed; a company's key is its primary domain lowercased with a leading www. removed. A domain on the configured free-mail list is never a company key. Creating or changing a record to a key another record already holds returns 409 with that record's ID and writes nothing. A record with no key is created and edited normally, and signals never link to it automatically. Orbit never merges records by name similarity, fuzzy match, or score. Policy: record.identity.v1; default: the rules in this clause.
  4. RECORD-004
    Duplicate merge. Merging two contacts or two companies requires an operator to choose the surviving record and the value of every conflicting field. The merge moves associations and timeline entries once, retires the other record's key as an alias so later signals carrying it link to the survivor, creates no signal, recommendation, or outreach, and records the retired ID in the audit trail.
  5. RECORD-005
    Timeline. A record's timeline lists its signals, stage and owner changes, notes, logged calls and meetings, recommendations, drafts, outbound attempts, replies, and merges, most recent occurred time first with ties broken by ID. Every entry shows its occurred time, its recorded time, and the operator, source, or feature that created it.
  6. RECORD-006
    Search and views. Operators can search contacts, companies, opportunities, and timeline text, and can filter opportunities by state, stage, owner, band, and queue. A first page of at most 50 matches returns within 500ms.
  7. RECORD-007
    Ownership. An opportunity has zero or one owner. Any operator can assign or reassign it, and the change appears on its timeline. Policy: opportunity.assignment.v1; default: a new opportunity is unassigned.
  8. RECORD-008
    Import. Operators import contacts and companies from a CSV, mapping its columns to fields once per import. A row updates an existing record only when it carries an Orbit ID or matches exactly one key under RECORD-003; a row matching more than one record fails. The import reports created, updated, and failed rows with row numbers and reasons, and writes nothing for a failed row.
  9. RECORD-009
    Duplicate candidates. Orbit lists contacts sharing a name within one company, and companies sharing a name, as duplicate candidates; names are compared lowercased with runs of whitespace collapsed. A candidate is a review item only: nothing is merged, altered, or hidden until an operator completes RECORD-004.
  10. RECORD-010
    Manual entries. An operator can add a note to any record and log a call or meeting with an occurred time, duration, and attending contacts. A manual entry is attributed to its author, editable and deletable by any operator, never sent to a customer, and never contributes to a score.
  11. RECORD-011
    Related records. A company page lists its contacts and its opportunities with each opportunity's stage, owner, and value, plus the total value of its open opportunities. A contact page lists their opportunities. Both reflect an association change on the next load.
  12. RECORD-012
    Contactability. A contact is contactable or do-not-contact. An operator can set do-not-contact at any time, and an unsubscribe event or a permanent bounce also sets it. No operation sends customer email to a do-not-contact contact, the state is shown wherever the contact appears, and only an operator can clear it.
  13. RECORD-013
    Deletion. Deleting a company detaches its contacts and opportunities and deletes neither. Deleting an opportunity deletes its recommendations, drafts, and unsent scheduled messages, and leaves its contacts, its company, and their entries for messages already sent. Deleting a contact follows DATA-002. Each deletion is confirmed before it runs.

SIGNAL 9 clauses

  1. SIGNAL-001
    Ingestion. A valid event from a configured source, carrying that source's signature, becomes one normalised signal within 10 seconds. The signal keeps its source, source event ID, type, subject, occurred time, received time, payload hash, and linking basis, and is never edited afterwards.
  2. SIGNAL-002
    Signal types. Orbit accepts form submissions; email sent, opened, replied, bounced, and unsubscribed events; meeting viewed, booked, completed, and cancelled events; page views; chats; content downloads; and firmographic changes. A source can add a type namespaced to itself, which changes no existing type. An event whose type is neither standard nor namespaced is rejected with 400.
  3. SIGNAL-003
    Idempotency. Repeated or concurrent delivery of one (source, source event ID) produces one signal and one set of downstream evaluations. Reusing that identity with a different payload hash is rejected and recorded as an error on that source.
  4. SIGNAL-004
    Linking. A signal links first by an Orbit record ID the source supplies, then by RECORD-003. A uniquely linked signal appears once on that record's timeline. A signal with no unique match is held in the unlinked queue, where it changes no score; an operator linking it later appends it to the chosen record's timeline exactly once and triggers one evaluation.
  5. SIGNAL-005
    Event time. A late or out-of-order event keeps its occurred time, appears in that position on the timeline, and triggers a fresh evaluation. It never overwrites a record field that a later-occurring event wrote.
  6. SIGNAL-006
    Evidence confidence. Every signal carries one confidence: observed, when the customer acted deliberately (form submission, reply, booking, meeting, download, chat), or inferred, when a tool reported activity (email open, page view). An inferred signal alone cannot create an opportunity, produce a high band, or satisfy ACTION-001's evidence requirement.
  7. SIGNAL-007
    No tracking. Orbit serves no tracking script, pixel, or cookie, and performs no fingerprinting or cross-site collection. A page-view, chat, or download signal is accepted only when its source supplies the visitor identity it already holds and the basis for holding it; without that basis the event is held unlinked under SIGNAL-004 and never becomes contact history.
  8. SIGNAL-008
    Ingestion failure. A missing or invalid signature returns 401, a request naming a source this deployment has not configured returns 403, and a payload over seed.json → limits.signalPayloadBytes returns 413; none of them writes anything. A persistence failure returns 503 and writes no partial signal, timeline entry, or evaluation, so the source can safely replay the same event identity. Each source shows its last accepted event, its last error, and its rejected-event count in settings.
  9. SIGNAL-009
    Signed sources. This clause supersedes BASE-ACCESS-004 for the paths /api/v1/signals/ and /api/v1/mail/events/ only: a request there is authorised by a signature from a source or mail provider configured in this deployment instead of an operator session, and may write only signals, delivery states, and their timeline entries. Every other mutation still requires a valid operator session and a server-side ownership check.

OPP 9 clauses

  1. OPP-001
    Lifecycle. An opportunity is open, won, or lost. Closing it as won or lost records the operator, the time, and a reason, and removes it from NOW and NEXT. Later signals append to its timeline and never reopen it; only an operator can reopen it, which returns it to open without changing its stage or owner.
  2. OPP-002
    Independent state. Stage, owner, score, band, and queue state are independent fields. A score or band change never changes stage, owner, or won/lost state, and a stage change never changes a score.
  3. OPP-003
    Evaluation. A linked signal whose type carries a non-zero weight in the scoring policy, or a change to an open opportunity's stage, expected close date, value, owner, or associations, evaluates that opportunity within 30 seconds. The result records a 0–100 score, a low, medium, or high band, the evaluation time, the policy version, and each contributing signal's contribution. A closed opportunity is not evaluated. Policy: opportunity.scoring.v1; default: each contributing signal's configured weight decays linearly to zero over the 30 days after its occurred time, the sum is clamped to 0–100, and 0–39 is low, 40–69 is medium, 70–100 is high.
  4. OPP-004
    Explainability. The opportunity view shows every signal the current score used, by ID, with its source, occurred time, confidence, and positive or negative contribution, and shows the reason for the current recommendation beside them.
  5. OPP-005
    Evaluation failure. If an evaluation fails or returns output that does not validate, the previous score, band, and evidence remain readable and are marked stale with the time of the failed attempt. Orbit shows no score, band, or recommendation it did not compute.
  6. OPP-006
    NOW ordering. NOW lists the open opportunities that OPP-007 placed there, ordered by score descending, then by the occurred time of their most recent contributing signal descending, then by ID. Operators can filter it by owner, stage, and band. Policy: opportunity.prioritization.v1; default: the ordering in this clause, and every factor it uses is shown in the opportunity view.
  7. OPP-007
    Queue entry. An open opportunity enters NOW when its band rises, a customer reply or delivery problem arrives, a scheduled message cannot be sent, its expected close date passes, its last timeline entry becomes older than the stale interval, or an operator puts it there. It is in NEXT while it waits for a scheduled send or for a customer response inside the awaiting-response interval, and in neither when no action is pending. The stale interval defaults to 14 days and the awaiting-response interval to 5 working days, counted Monday to Friday in the workspace timezone. Every entry, move, and removal records its reason and actor on the timeline.
  8. OPP-008
    Manual completion. An operator can complete or skip the current recommended action without sending anything, with an optional note; the outcome, note, and operator appear on the timeline. Policy: opportunity.next-action.v1; default: evaluate once, keep the opportunity in NOW if that produces a new recommendation, and otherwise remove it from NOW and NEXT.
  9. OPP-009
    Pipeline stages. The deployment has one pipeline. Its stages are named and ordered in settings; an opportunity can move to any stage in any order, and each move records the previous stage, the actor, and the time. A stage holding opportunities cannot be deleted until they are moved.

ACTION 5 clauses

  1. ACTION-001
    Current recommendation. An open opportunity has at most one current recommended action, which is either an email follow-up or a manual action. It names the action, cites at least one observed signal by ID, and records the policy or model version that produced it. Its written explanation is generated under AI-001 and is absent when AI-003 applies.
  2. ACTION-002
    Replacement. A new contributing signal, a changed opportunity, a completed or skipped action, or an operator request replaces the current recommendation. The replaced one stays on the timeline marked superseded and can no longer be drafted from, sent, or completed.
  3. ACTION-003
    Draft on request. An operator can request a one-to-one email draft for the current recommendation. Generation reads the opportunity, the primary or operator-selected contact, that contact's company, the cited signals, the messages already exchanged with that contact, and the configured instructions, and sends nothing. Policy: outreach.instructions.v1; default: at most 150 words, and no fact, price, discount, or commitment that a cited record or signal field does not carry.
  4. ACTION-004
    Durable draft. Recipient, subject, and body are visible and editable, and the draft is stored with its author, source recommendation, created time, and last edit time, and is readable after signing out and back in.
  5. ACTION-005
    Stale draft. A reply, meeting, unsubscribe, do-not-contact, permanent bounce, changed recipient, changed opportunity, or replaced recommendation marks a draft stale. A stale draft is shown as stale, and sending it returns 409 and writes no outbound message until an operator opens it, sees what changed, and confirms.

OUT 12 clauses

  1. OUT-001
    Human send boundary. No signal, score, recommendation, draft, job, or AI result can approve or start a customer message. A send requires an authenticated operator who has seen the exact recipient, subject, and body to invoke it, and a worker may dispatch only the unchanged content an operator approved for the schedule in OUT-009. No policy, adapter, extension, or setting removes this requirement.
  2. OUT-002
    Message states. Customer mail is submitted through mail.sender.v1. An outbound message is draft, scheduled, queued, reconciling, accepted, delivered, bounced, failed, cancelled, or delivery-unknown. The operator view calls a message sent only after the provider accepts it, and delivered only after a delivery event.
  3. OUT-003
    Send idempotency. Repeated or concurrent use of one send idempotency key creates one outbound message and at most one provider submission.
  4. OUT-004
    Threading. An outbound message carries message and reference headers that return the customer's reply to the same opportunity. A reply carrying those headers is attached once; a reply without them becomes an unlinked activity for operator review rather than a subject-based guess.
  5. OUT-005
    Accepted outcome. When the provider accepts a submission, one local transaction records the reviewed content and provider message ID as a timeline activity, completes the recommendation, sets the next action to awaiting response, moves the opportunity from NOW to NEXT, and creates one notification for the responsible operator. A replayed provider event repeats none of it.
  6. OUT-006
    Delivery failure. A transient submission failure retries up to 5 times over 1 hour. A permanent failure or an exhausted retry returns the opportunity to NOW, notifies the responsible operator once, and shows the provider's reason on the message. A permanent bounce also sets the contact do-not-contact under RECORD-012.
  7. OUT-007
    Stop conditions. A reply, a booked meeting, an unsubscribe, a do-not-contact, or a permanent bounce cancels that contact's scheduled messages and marks their unsent drafts stale under ACTION-005. A reply or a bounce ends awaiting response and returns the opportunity to NOW with the reply or the delivery problem as its next action.
  8. OUT-008
    Quiet hours. A draft can be written at any time. Sending outside 08:00–18:00 Monday to Friday in the contact's timezone, or the workspace timezone when the contact has none, requires a second confirmation naming the recipient's local time; a scheduled send waits for the next permitted minute. Policy: outreach.quiet-hours.v1; default: the window in this clause, with no holiday calendar.
  9. OUT-009
    Scheduled send. An operator can schedule one reviewed message for a future time and cancel it until it dispatches. Dispatch re-checks ACTION-005, RECORD-012, OUT-007, OUT-008, and OUT-010 against the current record and submits only the approved content; a stale or prohibited message is not sent, returns the opportunity to NOW, and shows the reason.
  10. OUT-010
    Sending limits. The per-minute deployment limit and the per-operator rolling-day limit in seed.json → limits are checked before submission. A message over a limit stays unsent and visible with the limit that stopped it and the time it may be sent; Orbit neither retries it silently nor merges it with another message.
  11. OUT-011
    Unresolved submission. Orbit records the outbound intent and its provider idempotency key durably before submitting. If the transaction in OUT-005 fails the message becomes reconciling; if the provider's response is a timeout it becomes delivery-unknown. In both states a job queries the provider by that idempotency key every 5 minutes for up to 24 hours, submits nothing again, and applies the OUT-005 outcome exactly once if acceptance is confirmed. A message still unresolved after 24 hours becomes a failure the operator can see, and notifies the responsible operator.
  12. OUT-012
    Unsubscribe. Every outbound customer message carries List-Unsubscribe and List-Unsubscribe-Post headers handled by the mail provider. An unsubscribe event from the provider sets that contact do-not-contact under RECORD-012 within 60 seconds and cancels their scheduled messages.

AI 4 clauses

  1. AI-001
    Provider and input. Recommendation explanations and email drafts go through ai.provider.v1. The request preview shows the operator every field, timeline entry, and instruction the request will carry, and nothing outside the preview is sent.
  2. AI-002
    Output validation. AI output must validate against its operation's schema and cite only evidence IDs present on the record. Output failing either check fails visibly and is never repaired with invented content or a semantic fallback. Only a transient transport failure is retried, at most twice within 30 seconds.
  3. AI-003
    Provider failure. When the AI provider is unconfigured or unavailable, records, signal ingestion, linking, scoring, queue placement, search, manual updates, hand-written drafts, and sending all continue to work, and a recommendation still names its action and evidence. A generation request shows the failure and produces no explanation or draft.
  4. AI-004
    Cost. Every AI call records provider, model, input and output tokens, feature, duration, status, and estimated cost. Operators can view totals by day and by feature in settings.

NOTIFY 2 clauses

  1. NOTIFY-001
    Responsible operator. The responsible operator for an opportunity is its owner, or, when it is unassigned, the operator whose action appears most recently on its timeline. They receive one in-app notification when it enters NOW, when a customer reply arrives on it, and when one of its outbound messages fails, bounces, or becomes delivery-unknown. When an unassigned opportunity that no operator has acted on enters NOW, every operator is notified instead. Duplicate source or provider events add no notification.
  2. NOTIFY-002
    Read state. A notification is unread until the operator opens it or marks it read. The unread count updates within 5 seconds and never counts one event twice.

PUBLIC 4 clauses

  1. PUBLIC-001
    Landing page. GET / returns 200 without an operator session, takes its name, description, and images from ext/config.ts, and links to magic-link sign-in. It shows no contact, company, opportunity, or signal from this deployment.
  2. PUBLIC-002
    Safe demo. When enabled in ext/config.ts and configured with the explicit PUBLIC_DEMO_OPPORTUNITY_ID binding, GET /demo/ loads one deliberately published opportunity from the dedicated hosted demo deployment after the visitor starts it. The opportunity and its observed evidence, recommendation, and publish-safe draft are created through Orbit's real operator workflow; no fixture or runtime mock is used. The visitor can edit and preview the follow-up entirely in the browser. The page states before loading and after preview that nothing is sent and no record changes. The browser makes no write request and calls no mail adapter, AI adapter, signal endpoint, or notification. The public endpoint cannot enumerate or select another record, and omits private addresses and raw signal payloads. Turning it off in ext/config.ts, or omitting the explicit binding, makes /demo and /demo/ return 404. This wording records the owner-authorized 13 September 2026 ruling that replaced the earlier browser-generated sample method while preserving its safety purpose.
  3. PUBLIC-003
    Unconfigured sign-in. While no mail-auth adapter is configured, GET /signin returns 200 without an operator session and states that magic-link delivery is unavailable. It presents no credential field, demo account, local-login action, or session bypass.
  4. PUBLIC-004
    Native sign-in. Configured magic-link delivery sends only to an existing active operator, gives the same request response for unknown and inactive addresses, and exchanges a hashed, single-use link within 15 minutes for a secure native session. Return locations stay inside the operator app. Sign-out revokes that session. A missing or failed mail configuration cannot issue a session.

DATA 2 clauses

  1. DATA-001
    Export contents. The export contains contacts, companies, opportunities, associations, source configuration without secrets, signals, evaluations with their policy versions, recommendations, drafts, outbound messages with their provider statuses, timeline activities, notifications, settings, and audit entries as JSON.
  2. DATA-002
    Contact erasure. Within 5 minutes of an operator deleting a contact, their email addresses, signal payloads, drafts, message bodies, and the notifications naming them are absent from records, search results, exports, and every later AI or mail request. Only audit entries survive, with the contact's reference anonymised, as BASE-DATA-003 requires.

Baseline

Selected ownership clauses from the 22 in the project’s BASELINE.md. They are declared requirements; evidence is recorded separately.

  1. BASE-DATA-005
    Independence. The deployment makes no request to the marketplace or the seed author. There is no telemetry, phone-home, licence check, or kill switch.
  2. BASE-DATA-001
    Export and import. pnpm export produces every record and attachment; pnpm import restores it into an empty deployment; export, import, export yields an archive with equivalent contents.
  3. BASE-DATA-004
    Outbound flows. User data leaves the deployment only through externals declared in seed.json → externals. No other outbound request carries user data.
  4. BASE-PUBLIC-001
    Privacy. Public surfaces (widgets, booking pages, forms, status pages) set no cookies, load nothing from third-party domains, and send no visitor data before the visitor's first interaction.
  5. BASE-SECRET-001
    No leakage. No secret appears in the client bundle, in logs, or in an error response.

View as agent

Everything on this page is in these files, copied unmodified from the release. An agent evaluating Orbit can read them instead of the page.

ACCEPTANCE.md
What the publisher accepts as a finished release.
AGENTS.md
Instructions for the coding agent that maintains an installation.
AUTHORING.md
How the project’s source is authored from shared components.
BASELINE.md
The baseline requirements the project declares.
CONTRACT.md
The requirements on this page, in source form.
HANDOVER.md
Maintainer orientation and verification status.
OPERATIONS.json
The machine-readable operating description.
OPERATIONS.md
How the project is set up, operated and deployed.
README.md
Source setup, available commands and implementation status.
edition.json
The source recipe: which shared components the project selects.
seed.json
The manifest: capabilities, outside services, extension points, limits, operating cost and deployment needs.
sources.lock.json
The locked bytes of those components.

Every project, with its availability, is in /agents/catalogue.json; the agents page describes the machine-readable files.