Brook
In development
Email-first support with recorded customer evidence and operator-approved Stripe refunds.
Brook 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
- Support
- Licence
- MIT
- Version
0.2.0- Requirements
- 92 clauses
- Publisher’s stage
- Bounded operator-approved refund workflow verified locally (Workers/D1 and desktop/mobile browser); hosted provider sandbox and full retained contract acceptance pending.
- Instead of
- Freshdesk
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.
cloudflare-platform- Cloudflare Worker, D1 and optional Email Routing host owner-controlled application data and inbound email.
sendgrid- Delivers operator-approved customer mail and native sign-in links.
stripe- Authoritative payment evidence and explicitly approved refunds.
Scope and limits
One business, native operator sessions, shared requests.
What it will not do
- multiple workspaces or tenants
- granular roles, groups, or private queues
- chat widgets, social, SMS, voice, or a public help centre
- outbound campaigns or a generic workflow builder
- automatic semantic ticket merging
- autonomous AI replies, state changes, or external actions
- external commerce mutations other than refunds
- a reporting module beyond the figures the situation board defines
- a library of operator-maintained canned replies
- marketing engagement signals such as email open and click rates
- native mobile applications
- arbitrary outbound webhooks
- a built-in payment or commerce system
- malware scanning
Extension points
Optional conveniences for common changes. Owners can change any source, including core logic, schema and infrastructure.
mail.sender.v1commerce.payments.v1
Declared limits
- Status
- unverified-load-capacity
- Note
- No load capacity claim; inbound parsing refuses messages over 2 MB.
- Inbound Message Bytes
- 2,000,000
Requirements
All 92 clauses of Brook’s CONTRACT.md. They say what the project must do; the handover and verification records say what is built and tested.
HOME 1 clause
HOME-001Owner identity plate.GET /presents the configured owner name, one configured statement of what the internal support workspace is for, and a sign-in link to/signin. It contains no pricing, feature tour, testimonials, metrics, or other marketing fabrication. When the configured credit toggle is enabled (its default), the footer contains the plain static linkPowered by Brook · runeditrun.com; rendering it makes no request to that site, the seed author, or any other third party.
OPS 3 clauses
OPS-001Equal operators. Every operator can see and act on every ticket, customer, view, and setting except where a policy restricts a specific action. There are no roles, and no filtered list or assignment restricts who may open or act on a ticket.OPS-002Management. Operators are invited and removed in settings. Any operator may invite. Any operator may remove any other operator, except the operator configured at setup, whom only they themselves can remove. A removal that would leave the deployment with no operator is rejected. Removing an operator unassigns their tickets and leaves their past messages, notes, and audit entries attributed to them. Policy:operator.management.v1; default: any operator may invite or remove within these rules. A replacement may narrow who may invite or remove; it can never permit last-operator removal.OPS-003Optimistic concurrency. Every ticket mutation includes the expected ticket revision. A stale revision returns409with the current revision and creates no message, property change, status change, external action, or other partial effect.
MAIL 16 clauses
MAIL-001Inbound email. An inbound message that passes MAIL-002 and parses as an RFC 5322 message becomes a ticket, or appends to an existing ticket under MAIL-004, within 60 seconds. It creates no ticket when MAIL-014 quarantines it or CUST-006 blocks its sender. The stored message preserves the sender, every recipient, the subject, the text and sanitised HTML bodies, the threading headers, the provider's received time, and the accepted attachments.MAIL-002Verified callbacks. Every mail-provider webhook, including intake and delivery-status callbacks, is processed only after its configured signature is verified; an invalid signature returns401and creates no record, job, ticket, message, or attachment.MAIL-003Delivery deduplication. Re-delivery of the same provider event or RFCMessage-IDproduces one inbound message and records the duplicate as a no-op.MAIL-004Conservative threading. An inbound email appends to a ticket only when itsIn-Reply-Toheader, itsReferencesheader, or the ticket reference of TKT-016 identifies that ticket and the sender is a known participant under MAIL-013; otherwise it creates a new ticket. Sender, subject, or body similarity alone never merges mail. The activity timeline records which of the three identifiers matched.MAIL-005Multiple support addresses. One RFC message addressed to more than one configured support address creates one inbound message. The ticket records every matched address and the single address it will reply from, which is the first match in the order the addresses are configured.MAIL-006Reply submission. Submitting a reply with a new idempotency key atomically creates onependingoutbound message and one dispatch job. Reusing the key returns the original message and creates no additional dispatch.MAIL-007Dispatch outcome. Provider acceptance changes the message toacceptedand records the provider message ID and threading headers within 60 seconds; acceptance does not mean delivery. Definitive transient failures are retried with the same provider idempotency key for at most five total attempts during one hour. A permanent failure becomesfailed; an ambiguous outcome becomesneeds_reviewand is not retried automatically.MAIL-008Delivery reports. A verified provider report changes an accepted message todelivered,delayed,bounced, orrejectedand records the report time. Brook never labels a message delivered without an authoritative delivery report.MAIL-009Automatic mail. An inbound message is non-actionable when it carries anAuto-Submittedheader whose value is notno, aList-*header,Precedence: bulk, or a delivery or read receipt, or when its sender's local part isno-reply,noreply,mailer-daemon, orpostmaster. Non-actionable mail is retained and shown on the ticket but does not reopen it, notify operators, or trigger AI. Every other inbound customer message is actionable; clauses elsewhere use these two terms with this meaning.MAIL-010Email attachments. Accepted inbound attachments are private ticket attachments. An attachment rejected by the limits inseed.jsonleaves the message readable and records the filename and rejection reason; outbound attachments travel within those same limits.MAIL-011Intake durability. Brook acknowledges a verified intake callback only after a durable intake record exists. Failure before that returns503so the provider redelivers, and creates no partial ticket. A parse, storage, or enqueue failure after the intake record exists marks that record visibly failed with a retryable or terminal reason.MAIL-012Participants. A new inbound ticket records the sender as requester and non-supportToandCcaddresses as participants;Bccrecipients are never disclosed. Operators may add or remove participants. A reply addresses the requester and current participants, excluding configured support and no-reply addresses.MAIL-013Participant threading. For MAIL-004, a known participant is the current requester or participant. A removed or unknown sender does not qualify even when the message contains a valid threading header or ticket reference.MAIL-014Unknown destination. A verified message with no configured support destination is quarantined without creating a ticket or message and displays the received destination and quarantine reason to operators.MAIL-015Outbound identity. A reply or acknowledgement is sent from the address the ticket recorded under MAIL-005, with the display name and signature configured in settings appended as the final block of the body, and carries the ticket reference of TKT-016 in the subject and in a Brook-issued header. Operator notifications instead use the no-reply sender of NOTE-005 and carry no signature.MAIL-016Acknowledgement. When acknowledgement is enabled in settings, the actionable message that creates a ticket produces exactly one automatic acknowledgement, stored as an outbound message on the ticket and subject to MAIL-006 through MAIL-008. No acknowledgement is sent for a ticket an operator created (TKT-014), for non-actionable mail (MAIL-009), for a blocked customer (CUST-006), or a second time on the same ticket.
TKT 17 clauses
TKT-001States. A ticket isnew,in_progress,waiting_on_customer,on_hold, orresolved. “Resolve & Close” setsresolved;closedis not a separate state. Every status change records the actor, previous state, next state, and time.TKT-002Customer reopen. An actionable message from an unblocked customer on aresolved,waiting_on_customer, oron_holdticket atomically appends the message and changes the ticket toin_progress. Policy:ticket.reopen.v1; default: retain the assignee and recalculate deadlines.TKT-003Properties. Operators can set priority (low,medium,high, orurgent), issue type, assignee, status, case-insensitive canonical tags, and configured ticket custom fields. Issue types and closure reasons are chosen from lists operators edit in settings. Each change records the actor, previous value, new value, and time in the activity timeline.TKT-004Assignment. New tickets are assigned by the assignment policy, and operators can assign or reassign them. An assignee removed under OPS-002 leaves the ticket unassigned. Policy:ticket.assignment.v1; default: leave new tickets unassigned.TKT-005Replies and notes. A reply is customer-visible and enters the email delivery lifecycle. A private note is visually distinct from a reply, is never delivered to the requester or a participant on any channel, and is never used as the body of a reply or acknowledgement. Notes are included in the export required byBASE-DATA-001.TKT-006Resolve. Resolving a ticket requires an explicit confirmation that shows the reply, the status change, the closure reason selected from the settings list, and any external action. The result records each part independently with its own outcome, so a failed email or external action is never presented as successful, and the stored closure reason is the one confirmed.TKT-007Filtered lists. Operators can list tickets by any combination of status, priority, assignee, tag, issue type, source, deadline tier (QUEUE-002), and customer, with counts derived from the same filters.TKT-008Operational sort. The default order is breached first, then nearest active deadline, then priority fromurgenttolow, then most recent customer activity, then ticket reference. Operators may instead sort by newest or oldest customer activity, with ticket reference as the final tiebreak.TKT-009Search. Search covers ticket reference, subject, message text, note text, customer and participant names and email addresses, and surfaced order, charge, and refund identifiers, labels the field that matched, and returns within one second.TKT-010Manual merge. Operators may irreversibly merge duplicate tickets by choosing a primary; messages and attachments are ordered chronologically, each secondary ticket becomes a link to the primary and keeps its own reference, no customer message is sent, and the actor and reason are audited. Policy:record.destructive-actions.v1.TKT-011Deletion. Deleting a ticket removes its messages and attachments underBASE-DATA-003. Policy:record.destructive-actions.v1.TKT-012Unread. A ticket is unread for an operator until they open it after the latest customer message; queue and navigation counts use that operator-specific state.TKT-013Activity timeline. Each ticket presents one chronological timeline of inbound messages, replies, notes, property and participant changes, threading decisions, delivery attempts and delivery reports, AI analyses, external actions, follow changes, feedback results, merges, and references to deleted records.TKT-014Manual creation. An operator can create anewticket for an existing customer with a subject and optional private note. Its source ismanual; a ticket created from inbound mail has sourceemail, and these are the only two values TKT-007 filters on. Creation sends no customer message; any later reply follows the MAIL-006 delivery lifecycle.TKT-015Manual reopen. An operator can reopen a resolved ticket toin_progressafter confirmation; the action retains its history and previous closure reason, records the actor and reason, and recalculates deadlines underticket.reopen.v1.TKT-016Ticket reference. Every ticket has a reference that is unique for the life of the deployment and never reused after deletion or merge. It is shown wherever the ticket appears, carried in outbound mail under MAIL-015, matched by MAIL-004, and accepted by search under TKT-009.TKT-017Following. An operator follows a ticket once they are assigned it, reply to it, or add a note to it, and any operator may follow or unfollow any ticket. Followers are the audience for the ticket notifications named in NOTE-001; unfollowing stops those notifications for that operator only and changes nothing else about the ticket.
CUST 9 clauses
CUST-001Creation. The first actionable inbound email from an address matching no customer creates one customer and links the ticket to it.CUST-002Email identity. Email addresses are compared case-insensitively after normalisation, and one address identifies one customer unless an operator explicitly merges records.CUST-003Profile. A customer has name, email addresses, phone, address, preferred channel, preferred language, marketing preference, segment, tags, and configured customer custom fields; operators can edit them with every change audited.CUST-004Context. A customer profile lists their tickets with reference, subject, status, assignee, last update, and feedback rating, and their satisfaction score under FB-004. When adapters are configured it also lists recent orders, payments, refunds, spend, and the provider retrieval time of each. Every figure shown is derived from data the deployment holds or from a named adapter response.CUST-005Merge. Operators may irreversibly merge two customers by selecting the surviving record; tickets, notes, and provider links follow it, conflicting fields are resolved explicitly, and the action is audited. Policy:record.destructive-actions.v1.CUST-006Blocking. An operator can block a customer. Inbound mail from a blocked customer is retained as non-actionable blocked activity on the ticket MAIL-004 selects, or as a visible blocked-intake record when MAIL-004 selects none. It creates no ticket, reopen, operator notification, acknowledgement, or AI work. Unblocking affects only later messages.CUST-007Erasure scope. Deleting a customer removes their tickets, messages, notes, attachments, feedback results, and locally stored commerce references underBASE-DATA-003; retained audit entries anonymise the customer reference. Policy:record.destructive-actions.v1.CUST-008Manual creation. An operator can create a customer with a name and at least one normalised email address. If that address already identifies a customer, Brook opens the existing record and creates no duplicate.CUST-009Customer notes. Operators can add, edit, and delete dated notes on a customer. A customer note records its author and time, is never sent to the customer, is attached to no ticket, and is included in the export.
QUEUE 7 clauses
QUEUE-001Situation board. The situation board shows, for the currently selected filter: the open backlog; the count of urgent tickets; the count in each deadline tier of QUEUE-002; the number resolved today; the mean first-response time of QUEUE-007 over the last 24 hours; the satisfaction score of FB-004 over the last 7 days; and, for each state of TKT-001, the count and the longest current wait. Every count is derived from the tickets the equivalent TKT-007 filter returns and opens that filter when selected. The board displays data no more than 30 seconds old together with the time of the data it is showing.QUEUE-002Deadline tiers. An active ticket's nearest unmet first-response or resolution deadline places it in exactly one tier:breachedonce the deadline has passed,at_riskwhen it is two hours or less away,due_soonwhen it is more than two and at most six hours away, andlaterbeyond that. Remaining time is measured on the same basis as the deadline itself (QUEUE-003). Breached tickets are counted and displayed separately fromat_risk.QUEUE-003Business calendar. Settings define one IANA timezone, weekly working hours, and dated holidays. Deadline calculations consume only configured business time unless the deadline policy chooses calendar time.QUEUE-004Deadline targets. First-response and resolution targets are calculated from ticket priority and the business calendar. Policy:ticket.deadlines.v1; default first-response/resolution targets in business minutes are urgent 15/120, high 60/480, medium 240/1440, and low 480/2400.QUEUE-005Deadline display. Every active ticket shows the applicable target, calendar basis, absolute due time with timezone, and time remaining or breached; a recalculation records its reason and the previous due time.QUEUE-006Breach behavior. Crossing a deadline marks the ticket breached and emits one notification event but never closes, resolves, or reassigns it.QUEUE-007Measured times. A ticket's first-response time is recorded when its first operator reply is accepted; an acknowledgement under MAIL-016 is never a first response. Its resolution time is recorded when it first becomesresolved. Both are stored as elapsed business time and elapsed calendar time, are shown on the ticket, and are the values QUEUE-001 averages. Reopening never overwrites a recorded first-response time.
GUIDE 4 clauses
GUIDE-001Policies. Operators can create, edit, retire, and view versioned resolution policies; a retired version remains readable from historical tickets that cited it.GUIDE-002Policy match. A resolution plan that relies on a policy identifies the exact policy version and the matching passage in the operator view.GUIDE-003Historical evidence. Editing a policy affects only future analyses; stored plans retain the policy version and evidence originally used.GUIDE-004Internal articles. Operators can create, edit, and retire versioned internal knowledge articles with a title and body; AI may cite an active version, and historical citations continue to open the version originally used. Articles are never published to a customer-facing surface.
AI 11 clauses
AI-001Resolution plan. Each actionable new or reopened ticket queues an AI resolution plan, and an operator may refresh it. The plan appears within 30 seconds when the provider responds and contains a recommended next action, confidence, and evidence.AI-002Evidence provenance. Every fact used by a plan, draft, or summary identifies its source type, source record, and retrieval time; operators can open the local source detail before acting.AI-003Grounding failure. A fact whose evidence is missing, older than the adapter's declared freshness window, or contradicted by another source is labelled unknown or conflicting. A plan in that state produces no recommended action, no draft asserting the fact, and no claim that an action succeeded.AI-004Suggested reply. When an operator requests a suggested reply, Brook prepares an editable reply in the composer; only an operator can submit it, and the outbound message records that AI supplied the draft and whether the operator edited it.AI-005Triage. AI sets the ticket's issue type and a sentiment ofpositive,neutral, ornegativewithin 30 seconds of an actionable customer message. It never overwrites an issue type an operator set, and an ungrounded classification remains unset rather than being replaced with a guessed default.AI-006Summary. An operator can request a stored summary of a ticket. The summary records when it was produced, links to the messages and evidence it covers, and is shown alongside the ticket timeline, never in place of it.AI-007No autonomous effects. AI cannot send mail, add a customer-visible message, change ticket or customer state, or invoke an external action. No policy or instruction may grant those effects.AI-008Provider failure. AI calls go through the requiredai.provider.v1adapter. If a configured provider times out or fails at runtime, the affected plan, draft, triage, or summary shows the error, stores no partial result, and leaves email and human ticket handling available.AI-009Cost. Every AI call records feature, provider, model, input and output units, latency, and estimated cost, whether it succeeded or failed; settings show totals by day and feature.AI-010Instructions. The plan-instructions policy selects buyer-supplied instructions for analyses and drafts but cannot widen the permitted data scope, change authorisation, or bypass AI-007. Policy:ai.plan-instructions.v1; default: use active resolution policies and require concise, evidence-backed, operator-reviewed output in the customer's language.AI-011Stale results. Each AI request captures the ticket revision and request sequence. A result for an older revision remains in history marked stale and never replaces the current result.
ACT 12 clauses
ACT-001Linked evidence. When order or payment adapters are configured, Brook resolves customer and ticket references to orders, fulfilments, captures, refunds, and provider object IDs and displays the retrieval time.ACT-002Evidence failure. An unavailable adapter or failed lookup is shown as unavailable with its last successful retrieval time; stale fixture data is never substituted.ACT-003Proposal boundary. A refund is the only external mutation Brook performs; every other adapter call is a read. A recommended refund is a proposal only and has no external effect until an operator confirms it.ACT-004Refund eligibility. A refund may be proposed only when the eligibility policy accepts the linked payment and amount. Policy:commerce.refund-eligibility.v1; default: the charge belongs to the customer, the amount is positive, and it does not exceed the provider-reported refundable balance.ACT-005Explicit approval. Every refund requires an operator confirmation showing the adapter, operation, target provider object, amount and currency, customer, reply, and idempotency key. No policy or AI instruction may bypass the confirmation.ACT-006Idempotent ledger. Brook durably records an action ledger entry before dispatch. Repeating a request with the same idempotency key returns the original entry and never creates a second external mutation.ACT-007Action states. A refund action ispending,succeeded,failed, orneeds_review; the ticket shows provider references, attempt times, the approving operator, and the provider's latest response with card data and secrets redacted.ACT-008Uncertain outcome. A timeout or ambiguous provider response becomesneeds_reviewand is never retried automatically or replaced with a new refund.ACT-009Reconciliation. An operator can reconcile aneeds_reviewaction against the provider by recording the verified provider outcome and reference; reconciliation updates the existing ledger entry and never dispatches a mutation.ACT-010Combined resolution order. When one confirmation includes a refund, success reply, and resolution, Brook dispatches the refund first. Only authoritative refund success permits the reply to be dispatched, and only provider acceptance of that reply permits the ticket to becomeresolved. Failure orneeds_reviewstops later steps and displays completed and incomplete steps separately. Retrying reuses the original action and message idempotency keys.ACT-011Adapter failure. A terminal refund failure leaves the ticket unresolved unless the operator separately resolves it, sends no success claim, and remains visible for correction.ACT-012Bounded transport retry. A retryable transport failure known to have produced no provider effect may be retried at most three times with the original idempotency key; any ambiguity follows ACT-008.
NOTE 6 clauses
NOTE-001Notification events. Brook emails a notification for a new unassigned ticket, a direct assignment, a deadline breach, and an unattended customer follow-up, subject to the recipient's mute and quiet-hours settings. A new unassigned ticket goes to every operator; a direct assignment goes to the new assignee; a deadline breach and an unattended follow-up go to the ticket's followers (TKT-017), or to every operator when the ticket has none.NOTE-002Coalescing. Repeated customer messages or deadline events for the same ticket produce at most one notification of each kind between operator open-or-acknowledge cycles.NOTE-003Quiet hours. Per-operator quiet hours defer that operator's non-urgent notifications until the next allowed time, without delaying intake, deadline calculation, or another operator's notification. Policy:ticket.quiet-hours.v1; default: urgent and breached tickets bypass quiet hours; other email notifications wait.NOTE-004Notification failure. A notification delivery failure is retried under MAIL-007, becomes visible after terminal failure, and never blocks or rolls back the ticket event.NOTE-005No mail loops. Operator notifications and acknowledgements use a configured no-reply sender that is not a support destination. Mail addressed to that return path is rejected and never creates or reopens a ticket.NOTE-006Unattended follow-up. When an actionable customer message remains unopened for five minutes, Brook queues one unattended notification to the ticket's followers, or to every unmuted operator when the ticket has none.
FB 4 clauses
FB-001Resolution survey. A resolution email includes a signed customer-feedback link when the feedback policy enables it. No survey is sent to a blocked customer, and reopening a ticket before its survey is sent cancels it. Policy:ticket.feedback.v1; default: include one survey with the first customer-visible resolution reply.FB-002Feedback access. The feedback link discloses no ticket or customer detail beyond the business name, accepts one submission, and expires 30 days after it is sent.FB-003Feedback result. A customer can submit a whole-number rating from one to five with an optional comment. The result is stored with its submission time, appears on the ticket and the customer profile, cannot be edited by an operator, and does not reopen the ticket or trigger AI.FB-004Satisfaction score. A satisfaction score is the mean of the ratings received in the stated window, shown with the number of ratings it covers. A window with no ratings is shown as unavailable, never as zero.
DATA 2 clauses
DATA-001Full export contents. The portable export contains every ticket, message, attachment, customer, customer note, tag, resolution policy and version, internal article and version, AI analysis and usage record, feedback result, notification, setting, commerce reference and action-ledger entry, and audit record; it contains no secret.DATA-002Operational export. An operator may export the currently filtered ticket list as CSV with ticket properties, deadline tier, and measured times; this convenience export does not replace the complete archive required byBASE-DATA-001.
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 Brook 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.
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.
seed.json- The manifest: capabilities, outside services, extension points, limits, operating cost and deployment needs.
Every project, with its availability, is in /agents/catalogue.json; the agents page describes the machine-readable files.





