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.
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.v1operator.management.v1record.identity.v1opportunity.assignment.v1opportunity.scoring.v1opportunity.prioritization.v1opportunity.next-action.v1outreach.instructions.v1outreach.quiet-hours.v1signal.recorded.v1record.merged.v1opportunity.evaluated.v1opportunity.queue-changed.v1recommendation.created.v1outreach.scheduled.v1outreach.accepted.v1outreach.failed.v1notification.created.v1navigation.after.v1now.header.after.v1now.row.actions.v1contact.sidebar.after.v1company.sidebar.after.v1opportunity.header.after.v1opportunity.sidebar.after.v1opportunity.timeline.after.v1composer.context.after.v1settings.sections.after.v1mail.sender.v1ai.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
TEAM-001Equal operators. Every operator can view and act on every contact, company, opportunity, signal, activity, and notification. There are no roles and no private records.TEAM-002Management. 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.TEAM-003One 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.TEAM-004Removal 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
RECORD-001Core 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 inseed.json → customFieldEntitiesalso holds custom fields.RECORD-002Associations. 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.RECORD-003Identity 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 leadingwww.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.RECORD-004Duplicate 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.RECORD-005Timeline. 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.RECORD-006Search 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.RECORD-007Ownership. 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.RECORD-008Import. 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.RECORD-009Duplicate 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.RECORD-010Manual 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.RECORD-011Related 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.RECORD-012Contactability. 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.RECORD-013Deletion. 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
SIGNAL-001Ingestion. 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.SIGNAL-002Signal 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.SIGNAL-003Idempotency. 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.SIGNAL-004Linking. 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.SIGNAL-005Event 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.SIGNAL-006Evidence 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.SIGNAL-007No 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.SIGNAL-008Ingestion failure. A missing or invalid signature returns 401, a request naming a source this deployment has not configured returns 403, and a payload overseed.json → limits.signalPayloadBytesreturns 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.SIGNAL-009Signed 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
OPP-001Lifecycle. 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.OPP-002Independent 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.OPP-003Evaluation. 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.OPP-004Explainability. 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.OPP-005Evaluation 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.OPP-006NOW 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.OPP-007Queue 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.OPP-008Manual 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.OPP-009Pipeline 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
ACTION-001Current 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.ACTION-002Replacement. 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.ACTION-003Draft 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.ACTION-004Durable 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.ACTION-005Stale 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
OUT-001Human 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.OUT-002Message states. Customer mail is submitted throughmail.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.OUT-003Send idempotency. Repeated or concurrent use of one send idempotency key creates one outbound message and at most one provider submission.OUT-004Threading. 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.OUT-005Accepted 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.OUT-006Delivery 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.OUT-007Stop 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.OUT-008Quiet 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.OUT-009Scheduled 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.OUT-010Sending limits. The per-minute deployment limit and the per-operator rolling-day limit inseed.json → limitsare 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.OUT-011Unresolved 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.OUT-012Unsubscribe. Every outbound customer message carriesList-UnsubscribeandList-Unsubscribe-Postheaders 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
AI-001Provider and input. Recommendation explanations and email drafts go throughai.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.AI-002Output 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.AI-003Provider 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.AI-004Cost. 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
NOTIFY-001Responsible 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.NOTIFY-002Read 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
PUBLIC-001Landing page.GET /returns 200 without an operator session, takes its name, description, and images fromext/config.ts, and links to magic-link sign-in. It shows no contact, company, opportunity, or signal from this deployment.PUBLIC-002Safe demo. When enabled inext/config.tsand configured with the explicitPUBLIC_DEMO_OPPORTUNITY_IDbinding,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 inext/config.ts, or omitting the explicit binding, makes/demoand/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.PUBLIC-003Unconfigured sign-in. While no mail-auth adapter is configured,GET /signinreturns 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.PUBLIC-004Native 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
DATA-001Export 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.DATA-002Contact 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.
BASE-DATA-005Independence. The deployment makes no request to the marketplace or the seed author. There is no telemetry, phone-home, licence check, or kill switch.BASE-DATA-001Export and import.pnpm exportproduces every record and attachment;pnpm importrestores it into an empty deployment; export, import, export yields an archive with equivalent contents.BASE-DATA-004Outbound flows. User data leaves the deployment only through externals declared inseed.json → externals. No other outbound request carries user data.BASE-PUBLIC-001Privacy. 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.BASE-SECRET-001No 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.





