Lily
In development
A self-hostable ticket desk with numbered cases, shared views, Help Centre intake, configurable channels, service targets, customer records, and operational analytics.
Lily 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.1.0- Requirements
- 109 clauses
- Publisher’s stage
- thin-real-worker-d1-ui-port; ticket-desk-contract-draft
- Instead of
- Zendesk
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.
native-auth-mail- Cloudflare primitives do not originate transactional email; Lily uses the explicitly selected Resend or SendGrid transport to deliver native magic-link sign-in messages.
mail-provider- A configured provider supplies inbound delivery callbacks, outbound email transport, and authoritative delivery reports.
record-link-provider- A buyer-controlled adapter may expose named external records without making Lily an owned CRM or commerce system.
commerce-and-ai-provider- The retained optional specification requires replaceable commerce and AI providers while keeping manual core ticket work independent.
help-centre-ai-provider- Article-grounded generated visitor answers require a buyer-selected model provider.
voice-provider- A buyer-selected telephony service supplies phone lines, queue state, and call records that Cloudflare primitives do not originate.
external-sync-provider- A buyer-controlled provider transport is required only when that extension synchronises records outside Lily.
sendgrid- Optional explicitly selected provider for native sign-in, signed inbound mail, human-reviewed public replies, and signed delivery events. Provider acceptance is not delivery confirmation.
Scope and limits
One business, one shared support workspace, with role and group access controls.
What it will not do
- Multiple businesses or tenants
- A separately browsable conversation inventory
- An owned CRM, commerce, order, payment, fulfilment, or marketing system
- Zendesk community, badges, moderation, theme marketplace, dashboard sharing or restrictions, CRM suite/tasks/prospecting, native mobile SDK, or social connectors
- Application marketplace, classic report builder, vendor benchmark survey, product switcher, signup/trial/billing chrome, or workforce management
- Outbound campaigns, arbitrary external webhooks, native mobile applications, or voice recording
- Autonomous customer messages, ticket lifecycle changes, external mutations, or fabricated adapter data
- Freshdesk replacement or import until compliant mapped public-source evidence exists
Extension points
Optional conveniences for common changes. Owners can change any source, including core logic, schema and infrastructure.
app.route.v1app.navigation.v1settings.section.v1job.consumer.v1cron.task.v1ticket.assignment.v1ticket.auto-close.v1ticket.reply-status.v1ticket.followers.v1requester.suspension.v1channel.autoresponder.v1service-target.selection.v1automation.action-allowlist.v1ticket.quiet-hours.v1csat.request.v1ticket.created.v1ticket.message.received.v1ticket.message.sent.v1ticket.assigned.v1ticket.status.changed.v1ticket.merged.v1customer.updated.v1automation.run.completed.v1service-target.changed.v1satisfaction.received.v1app.navigation.after.v1home.dashboard.after.v1ticket.queue.row.actions.v1ticket.header.actions.after.v1ticket.timeline.after.v1ticket.composer.toolbar.after.v1ticket.requester-context.after.v1customer.profile.after.v1help.article.after.v1settings.after.v1mail.receiver.v1mail.sender.v1record.link.v1voice.provider.v1external.sync.v1commerce.platform.v1ai.provider.v1
Declared limits
- Status
- estimated
- Basis
- Capacity and rate values are not load tested and must be replaced by measured limits before the first release. Public request values are per-IP one-minute enforcement thresholds, not capacity proof. Attachment content types are a product decision, not a measurement.
- Concurrent Operators
- 25
- Tickets
- 50,000
- Messages
- 250,000
- Inbound Messages Per Minute
- 20
- Outbound Messages Per Minute
- 20
- Active Automation Rules
- 20
- Attachment Bytes Per File
- 10,485,760
- Attachment Bytes Total
- 10,737,418,240
- Attachment Content Types
- image/png, image/jpeg, image/gif, image/webp, application/pdf, text/plain, text/csv, message/rfc822, application/zip, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
- Public Requests Per Minute Per Ip
- Assets 240
- Health 60
- Landing 60
- Sign In 10
- Survey 30
- Provider Webhooks 120
- Integrations 120
- Help Centre 60
- Help Request 20
- Widget 30
Requirements
All 109 clauses of Lily’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-001Deployment front door.GET /presents the configured business name, a short configured description of its support service, links to the public Help Centre and configured public request surfaces, and a sign-in link to/signin. It contains no vendor pricing, trial, billing, product-switcher, or marketing claims.
APP 1 clause
APP-001Authenticated workspace. An authorised user entering/appcan reach Home, Views, Tickets, Customers, Help Centre, Analytics, Channels, and Administration according to their role. Navigation has a compact responsive form, global search, keyboard shortcuts for search/navigation/common ticket actions, contextual coach marks, and a dismissible setup checklist whose completed state is per Administrator. An unavailable optional channel or adapter is labelled unavailable with the configuration action rather than simulated data.
ACCESS 4 clauses
ACCESS-001Roles. Lily has Administrator, Agent, Contributor, and Light Agent roles. Administrators manage deployment-wide settings, people, groups, forms, roles, channels, and policies. Agents work tickets and public replies. Contributors can make internal contributions only. Light Agents have the explicitly configured limited ticket access. An authenticated person may perform only actions permitted by their role and any ticket/group restriction.ACCESS-002Groups and membership. Administrators create, rename, retire, and populate groups. A ticket can be assigned to a group and then an agent; group assignment is visible in views, history, filters, reports, and exports. Retiring a group requires an explicit reassignment or unassignment of its open tickets and retains historical attribution.ACCESS-003Authorisation and lifecycle. Administrators invite, suspend, restore, and remove agents. Removing an agent unassigns their active tickets and preserves the author identity on earlier messages, notes, and audit records. The last active Administrator cannot be removed. Agents configure their own signature and notification preferences; the configured signature is appended only to their public email reply.ACCESS-004Concurrent edits. Each case mutation supplies the revision it was based on. A stale mutation returns409and makes no partial field, status, note, assignment, automation, or outbound-message change. An accepted inbound message is durable even if it races with an agent edit.
TKT 18 clauses
TKT-001Creation. A human customer email to the support address or an agent's manual submission creates one ticket with an immutable ID, creation time, customer, channel, subject, initial message, declared ticket custom fields, and revision. A new ticket is Open with Normal priority unless the creating agent chooses another priority.TKT-002States and pending reasons. A ticket is Open, Pending, Solved, Closed, or Merged. Pending carries exactly one configured reason, and every reason declares whether it waits on the customer; a ticket is never Pending without a reason. Solved records an agent-confirmed outcome, Closed is immutable archival history, and Merged is an immutable redirect under TKT-016.TKT-003Customer reply. A qualifying human customer message on an Open, Pending, or Solved ticket appends to that ticket, makes it Open, and clears its pending reason. A message matching Closed creates a linked new ticket; a message matching Merged appends to the destination under TKT-016. No qualifying human customer message is discarded.TKT-004Auto-close. A Solved ticket closes seven days after it was last solved unless a qualifying human customer message arrives first. Closing never deletes messages, evidence, executions, or audit history. Policy:ticket.auto-close.v1; default: seven days.TKT-005Queues and views. Agents can filter tickets by status, pending reason, priority, assignee, group, tag, channel, service-target state, and ticket custom fields; sort by target due time, last activity, or priority; and save a named view that authorised agents can open. My queue lists Open and Pending tickets assigned to the current agent, earliest target due time first.TKT-006Search. Full-text search over ticket IDs, subjects, message bodies, customer names and email addresses, tags, and configured custom fields returns matching authorised tickets within 500ms at the stated limits.TKT-007Assignment. New tickets are assigned by the assignment policy. Agents may assign or reassign a ticket to one agent, one group, or both without changing state or service clocks. Policy:ticket.assignment.v1; default: unassigned.TKT-008Priority. Every ticket has Urgent, High, Normal, or Low priority. Authorised agents and allowed automation may change it; each change records actor, prior value, new value, and time.TKT-009Timeline. The ticket timeline presents customer messages, public replies, internal notes, system events, adapter evidence, automation runs, and execution records in durable event-time order, with insertion order as a stable tie-breaker across reload and pagination.TKT-010Public and internal messages. Public replies are eligible for customer delivery. Internal notes are a distinct stored kind that cannot be passed to a delivery adapter, included in customer-facing export, or used to claim an action completed.TKT-011Solved guard. Solving is an explicit agent action and sends no draft or external action. A Solved ticket rejects new public replies and external executions until it is reopened under TKT-003 or TKT-015; Closed and Merged tickets reject them permanently.TKT-012Concurrent changes. Each ticket mutation supplies its revision. A stale mutation is rejected with the current revision and makes no partial change; inbound message append never fails because of a concurrent agent edit.TKT-013Ticket merge. An agent may merge only tickets for the same customer, neither Closed nor Merged, after confirming source and destination IDs and a reason. The source becomes Merged and stores the destination ID. Cross-customer merge is refused; it needs a separately versioned, elevated extension with explicit participant and recipient reconciliation before customer-visible data could cross a customer boundary.TKT-014Manual tickets. An agent-created ticket records whether its initial message came from the requester or agent, and that attribution is immutable. Agent-originated tickets start no first-response clock and are excluded from first-response reporting.TKT-015Operator reopen. An agent may reopen Solved to Open with a required reason; it starts a new service cycle, sends nothing, and records the action. Closed and Merged tickets cannot be reopened.TKT-016Merged history and replies. A Merged ticket is read-only, its timeline is presented on the destination, replies addressed to stored threading identifiers reach the destination, and both IDs remain resolvable in search and audit history. Its source conversation stays linked to the immutable source and is transcluded on the destination with original conversation and author identity. Source and destination retain independent lifecycle and completion histories; routing or transclusion changes neither lifecycle.TKT-017Tags. Agents apply and remove case-insensitive canonical tags on tickets and customers; each change records actor and time. Tags filter queues, match search, serve as automation conditions and report breakdowns, and appear in export. Removing a tag retains the audit event.TKT-018Reply outcome. Sending a public reply leaves the ticket Pending with a configured reason that waits on the customer, unless the agent selects a different permitted status before sending. Sending never solves a ticket alone. Policy:ticket.reply-status.v1; default: Pending, waiting on the customer.
CASE 10 clauses
CASE-001Numbered case and default conversation. A Lily case is the visible numbered ticket. Its public number is unique for the deployment life, never reused after deletion or merge, and remains resolvable after import. Each new ticket creates one hidden conversation by default. Customer-visible messages live on that conversation; notes, evidence, assignment, actions, and lifecycle live on the case. Completion never closes or deletes the conversation.CASE-002View predicates and columns. A saved view has an All block and an optional Any block. It matches when every All condition matches and, when Any is non-empty, at least one Any condition matches; an empty All block is true and an empty Any block imposes no additional condition. Rows, counts, exports, dashboard drill-through, sorting, pagination, and selected columns use the same stored predicate.CASE-003Forms, followers, context, and work tabs. Administrators define ticket forms, required fields, and custom fields; creation preserves the selected form and submitted values. An authorised agent can add/remove followers, who receiveticket.followers.v1updates without needing to be owner or assignee. Detail exposes requester context, selected columns, filtered activity types, and configured tabs. Policy:ticket.followers.v1; default: assignment, requester message, note, public reply, at-risk, breach, and solved events notify followers subject to preferences.CASE-004Bulk and destructive work. An authorised agent can apply reviewed bulk assignment, tag, status, macro, or spam actions to a filtered selection with independent per-ticket success, skip, or failure outcomes. Spam marking, requester suspension, deletion, and restoration require the separately authorised destructive action and preserve audit history under baseline retention.CASE-005Agent and mobile work. Home presents assigned/followed work, capacity, activity, and queue links; availability influences only later routing. The responsive mobile workspace supports ticket work and each agent can configure mobile notification categories and quiet hours with the same routing and suppression semantics as NOTIFY-001 and NOTIFY-002.CASE-006Live conversation. A configured widget may keep a live visitor/agent conversation. Each live conversation has a visible participant and queue state, is linked to its ticket when a request is submitted or an agent creates one, and retains its message chronology when it becomes the ticket's hidden conversation. An agent presence indicator never claims a live responder when none is assigned.CASE-007Global and recent search. Global search returns authorised tickets, customers, organisations, Help Centre articles, agents, groups, and saved views, identifies the matched type and field, and keeps a per-agent recent-record list that can be cleared. Ticket full-text latency remains TKT-006; global results preserve access checks and do not reveal a recent record after access changes.CASE-008Work affordances. Agents can open concurrent ticket tabs without losing unsaved drafts, return to a chosen tab, and see its current revision or conflict state. A queue can offer an explicit guided next-ticket action based on its visible ordering; its action, selection rationale, and any skipped ticket are recorded. The exact guided-play interaction is a Lily decision because the available Zendesk capture establishes the surface but not its execution.CASE-009Tag entry. Ticket tags display as removable chips, offer existing canonical tags while typing, and permit an authorised agent to create a new tag inline. Each entry/removal is audited. Autocomplete and inline creation are Lily product requirements; the cited Zendesk evidence establishes display and removal only.CASE-010Rich composition, counters, and capacity. The composer persists rich formatting, emoji, links, and accepted attachments before submit. Workspace chrome shows authorised agents live conversation and assigned-work counters. Administrators set an enforced per-agent active-ticket cap; routing skips capped agents and records the reason, while direct assignment above the cap requires an explicit authorised override.
MAIL 14 clauses
MAIL-001Inbound email. A signature-verified provider delivery to a configured support address creates or appends a ticket message within 60 seconds, preserving sender, recipients, subject, sanitised text and HTML, attachments, provider ID, and threading headers.MAIL-002Threading. An inbound email appends only whenIn-Reply-ToorReferencesmatches a stored message ID, or a valid Lily-issued opaque reply token identifies its ticket, and its sender is the current requester or current participant. The timeline audits which identifier matched. A removed or unknown sender starts a new ticket even with a valid identifier; sender and subject alone never join mail.MAIL-003Threading conflict. An unmatched message starts a new ticket. Conflicting headers, or a valid token that disagrees with them, start a new ticket with a visible conflict event naming both candidate tickets; the message is never attached speculatively.MAIL-004Inbound idempotency. Replaying one provider event with the same provider message ID produces one stored message, one service-cycle effect, and at most one routing, acknowledgement, and automation effect. Provider-event ID and RFCMessage-IDare durably one-to-one. If either known identity arrives paired with a new, conflicting identity or immutable thread metadata, Lily quarantines the conflict without routing, service-cycle, acknowledgement, or automation effect until reviewed. Body equality never resolves it.MAIL-005Automatic mail. Mail with automatic, bulk, delivery-status, receipt, or no-reply signals is non-actionable. A matching item is stored as a visible system event and does not reopen, notify, start a service cycle, run automation, or request an acknowledgement. An unmatched item creates no queue entry and is retained as a discarded-mail audit record.MAIL-006Outbound email. A public reply atomically creates one durable outgoing message and one dispatch job with a stable idempotency key, reply headers, and a Lily-issued opaque reply token, then dispatches that job within 60 seconds. It uses the ticket's stored reply mailbox: the first configured support-address match retained from RFC intake under MAIL-011, or, for a manual, web-form, widget, or other non-RFC ticket, exactly one enabled configured support mailbox selected and stored by an authorised agent before its first public reply. A repeated key returns the original message and dispatch job.MAIL-007Delivery state. Each outgoing message monotonically progresses through queued, accepted, delayed, delivered, bounced, rejected, suppressed, failed, or needs_review. Provider acceptance is never customer delivery. There are at most five total dispatch attempts in one hour with the original key. A failure before provider acceptance never stops a first-response clock. Lily preserves provider-acceptance time and delivery evidence. If the sole qualifying public reply later reaches final bounced, rejected, or failed state, it restores that service cycle's original first-response clock and target due calculation without resetting elapsed time; if another qualifying public reply remains provider-accepted, the clock stays stopped. The pre-send ticket status and its mutation revision are recorded; on that same sole-reply final failure, Lily restores the pre-send status only when no later independent status mutation occurred, never clobbering later agent changes. Final failure or needs_review notifies under NOTIFY-004. An ambiguous needs_review outcome is never automatically retried and requires provider reconciliation.MAIL-008Authoritative delivery reports. Verified provider reports move an accepted message only forward to delivered, delayed, bounced, or rejected and record report time. Duplicate or out-of-order reports never regress a terminal state; Lily never labels delivery without an authoritative report.MAIL-009Attachments. Inbound and outbound attachments remain bound to their immutable message. A file outside the seed limits is rejected with filename and reason while the readable message and accepted files are retained.MAIL-010Provider events. Intake and delivery webhooks are rejected without a validmail.receiver.v1signature. Duplicate and out-of-order delivery events are tolerated and never create data or regress a terminal state.MAIL-011Recipients and support-address intake. One RFC message addressed to multiple configured support addresses creates one intake record, retains every matched support address, and records the first configured match as its reply mailbox. A new ticket records the sender as requester and only non-supportToandCcrecipients as participants; Bcc is never disclosed. A public reply addresses the requester and current participants the agent keeps in the composer; removed recipients are not restored later. Support and notification addresses are never participants.MAIL-012Intake durability and destination. Lily acknowledges a verified intake only after a durable intake record exists; failure before it returns503with no partial ticket. Post-record parse, storage, or enqueue failure is visible with a retryable or terminal reason. A verified message with no configured support destination is quarantined with destination and reason.MAIL-013Mailbox identity. An agent-authored public reply uses the ticket's stored reply mailbox: the first configured RFC support-address match under MAIL-011, or the authorised enabled configured-mailbox selection stored under MAIL-006 for a manual, web-form, widget, or other non-RFC ticket. It carries ticket threading data and appends that agent's configured signature. Operator notifications use a no-reply address that is not a support destination and carry no agent signature. Automatic acknowledgement is not a notification and follows MAIL-014.MAIL-014Automatic acknowledgement. When enabled, the actionable message that creates a ticket produces exactly one stored automatic acknowledgement under MAIL-006 through MAIL-008. It uses the ticket's stored reply mailbox and threading data but no agent signature; it is not sent from the no-reply notification address. No acknowledgement is sent for manual, non-actionable, blocked, or later ticket messages, and it never counts as a first response. Policy:channel.autoresponder.v1; default: disabled until an Administrator enables it for a mailbox.
CHAN 6 clauses
CHAN-001Channel catalogue. Administrators see every configured intake and delivery channel, its enabled state, form or mailbox binding, group routing, public address, and configuration health. Disabling a channel preserves its history and stops only later intake or dispatch through that channel.CHAN-002Web widget and simulator. A configured public widget collects a request with the configured form and creates a ticket under TKT-001. It identifies the current requester where consented, exposes the required privacy text, and confirms a successful request without pretending an agent is present. An Administrator can use a simulator to preview configured form, bot, appearance, proactive-message, and live-conversation states without creating a real ticket or sending a visitor message.CHAN-003Grounded bot assistance. A configured bot greets the visitor, offers up to ten article-grounded generated answers from approved Help Centre material, and shows cited article links. It stores every bot and visitor turn before agent handoff in the linked conversation, collects the ticket form, and hands off for no valid answer or visitor request. Coreai.provider.v1receives only approved article material and disclosed visitor input, never private notes; cited identifiers are validated against supplied articles and invalid output fails for review rather than falling back to invented copy.CHAN-004Proactive messages. An administrator can configure an eligible widget audience and a reviewed proactive message. The configuration states its trigger and frequency limit, respects consent and suppression, and records each presentation; it does not create a ticket unless the visitor submits a request.CHAN-005Voice queue and ticket link. A configured voice adapter exposes queues or lines with waiting-call count, agent or group routing context, call state, and stable Ticket ID when one exists. An authorised agent can attach a call record to an existing ticket; the attachment is audited and adds no invented call-to-ticket relation when no ticket was selected. This is a Lily lifecycle decision; the Zendesk evidence only establishes a Live Calls Ticket ID column.CHAN-006Side conversations. An authorised agent can open a labelled side conversation with an approved external participant, see its delivery state and replies on the ticket, and keep it separate from the customer-visible conversation. It cannot disclose private notes without an explicit reviewed message.
CUST 7 clauses
CUST-001Identity. The first qualifying customer message from an unseen normalised email address creates one customer; comparison is case-insensitive and a shared display name never merges identities.CUST-002Profile. A profile has display name, primary and observed email addresses, locale, tags, declared custom fields, and private account notes. Locally owned fields are editable and adapter-sourced fields are read-only with source and refresh time.CUST-003History. A profile shows every Open, Pending, Solved, Closed, and Merged ticket for that customer with its satisfaction and available adapter records.CUST-004Notes. Agents may add private, attributed customer notes. Notes are never sent to the customer or written back through an adapter.CUST-005Merge. An agent merges customers only after confirming survivor and source IDs and seeing addresses, ticket counts, and record links. Tickets, addresses, notes, tags, fields, and audit history move to the survivor; incompatible provider customer IDs block the operation and name the conflict.CUST-006Erasure boundary. Erasing a customer removes locally owned messages, attachments, notes, evidence snapshots, and tickets underBASE-DATA-003; it never claims to erase a provider account or provider data.CUST-007Resync suppression. This predecessor guarantee applies only to an enabledexternal.sync.v1extension described inresearch/optional-commerce-adapter.md: erasure stores a one-way keyed digest of normalised provider namespace and resource ID, no customer field, to prevent automatic resync recreation; it travels with export/import and only explicit restore removes it. Core Lily has no automatic external sync or sync credential.
CUSTOMER 2 clauses
CUSTOMER-001Organisations and suspension. Administrators create organisations and membership. An authorised agent may suspend a requester; Policy:requester.suspension.v1; default: new intake is quarantined for review while earlier history stays readable.CUSTOMER-002Imports and record links. An Administrator can run a reviewed CSV customer import with mapping, validation, duplicate handling, and per-row outcomes. An optional record-link adapter attaches named external records with adapter, identifier, link state, and retrieval time; unavailable data is labelled unavailable and never fabricated.
HELP 5 clauses
HELP-001Public Help Centre and audiences. An Administrator activates or deactivates the public Help Centre; deactivation makes public article and request paths unavailable while preserving authoring history. Published content is visible only to its named audience. An audience selects signed-in users, staff, groups, tags, and users with All/Any blocks: all All conditions and, when non-empty, one Any condition must match; empty All is true and empty Any adds no restriction. Administrators preview matching users and anonymous/staff roles. A preview is not evidence of signed-out deployment reachability.HELP-002Articles, taxonomy, history, and bulk work. Agents with article authority can create, edit, publish, unpublish, archive, and restore articles in categories and sections. Articles have a title, body, author, timestamps, lifecycle state, audience visibility, content tags, and version history. Article history is filterable by actor, event, and date. A selected article set supports reviewed bulk publish, unpublish, archive, restore, category, and audience changes with per-item success, skip, or failure results.HELP-003Findability and media. The Help Centre offers text search, category navigation, pagination, article metadata, a shared media library with upload, search, insert, and removal permissions, and article comments when comments are enabled. Search results respect audience visibility and label unavailable translations or attachments rather than substituting a different article.HELP-004Languages and appearance. Administrators configure Help Centre languages, translated article variants, branding, theme appearance, and a reviewed public preview. A language fallback is explicit and never represents untranslated copy as a translation.HELP-005Help Centre requests. A public request form uses an administrator-selected ticket form, validates required fields, creates a ticket under TKT-001, and gives the requester a result that does not expose another ticket. Its submission is distinguishable from article comments and widget intake.
ADMIN 2 clauses
ADMIN-001Operational settings. Administrators configure business hours, IANA timezone, holiday calendar, ticket types and priorities, statuses, forms, custom fields, canned replies, mailbox identities, routing, authentication, retention, and API/webhook credentials. Retention configuration can label, report, or schedule review of records but cannot automatically delete user data; deletion follows the applicable baseline clause and explicit authorised action. The settings screen distinguishes active configuration from unavailable optional adapters.ADMIN-002Business rules, capacity, and usage. Administrators can inspect routing rules, capacity limits, API/webhook integrations, installed approved applications, their last execution or error, and current storage/API/channel usage meters with source, period, and refresh time. No setting silently expands authorisation or gives an external application access beyond its configured scope.
MACRO 3 clauses
MACRO-001Macro library. Authorised agents create, edit, archive, and search shared macros for a public reply or internal note. A macro may propose tags, priority, assignment, form fields, or status, but does not itself send a message. The library reports applied count, recent use, and sortable rolling seven-day usage without exposing ticket content to an unauthorised viewer.MACRO-002Placeholders. Applying a macro resolves its declared placeholders from the current ticket, requester, organisation, and agent. An unresolved required placeholder blocks use and identifies the missing value.MACRO-003Review boundary. A macro fills an editable draft and previews every field change. Submitting remains an explicit TKT-018 and MAIL-006 action and cannot bypass revision, authorisation, or outbound delivery rules.
SLA 6 clauses
SLA-001Calendar and selection. Administrators configure first-response and resolution targets against one workspace timezone, working-hours schedule, and holiday calendar. Policy:service-target.selection.v1; default: targets are selected by ticket priority and measured in business time. A ticket with no matching target displays that fact and is excluded from met/breached denominators.SLA-002Snapshot and calculation. Starting a service cycle stores the target version, duration, due time, and business-calendar inputs. Later setting edits do not rewrite its result. Recalculation records its reason and prior due time.SLA-003First response. The first-response clock stops only when the first public agent reply is provider-accepted, subject to MAIL-007's sole-qualifying-reply final-failure restoration. Assignment, notes, macros, automation, an acknowledgement, and queued or failed delivery do not stop it.SLA-004Resolution cycle. The resolution clock runs for Open, and for Pending unless the selected pending reason explicitly waits on the requester. It stops when the case is solved. A requester message or agent reopen starts the next cycle while retaining prior cycles.SLA-005Visibility. Ticket rows, ticket detail, Home, and saved views show the exact due time, calendar basis, remaining or overdue time, and stateactive,paused,at_risk, orbreached. At risk begins at 25% of target duration remaining in business time.SLA-006Breach effects. Crossing a target marks the cycle breached, emits a notification event, and never resolves, closes, reassigns, or otherwise mutates the ticket on its own.
QUEUE 5 clauses
QUEUE-001Filter-exact dashboard. Home shows the current selected view's open backlog, urgent count, target-state counts, resolved-today count, mean first-response time over the last 24 hours, and satisfaction score over the last 7 days. For every ticket state it shows the count and longest current wait. Every count opens the equivalent saved-view conditions and shows the data timestamp; it is no more than 30 seconds old at the stated limits.QUEUE-002Target tiers. An active ticket with a target is exactly one ofbreachedonce past due,at_riskwith 25% or less of its target duration remaining,due_soonwith more than 25% remaining and two business hours or less to due, orlaterotherwise. A paused cycle ispaused; a ticket with no matching target isno_target. The four active-target tiers are mutually exclusive and exhaustive.QUEUE-003Operational ordering. The default work ordering is breached, at_risk, due_soon, later, paused, no_target, then nearest active due time, priority, latest requester activity, and ticket number. An agent may choose documented alternatives without changing the selected view conditions.QUEUE-004Due-state detail. A queue and ticket disclose which target is due, absolute due time with timezone, and the previous/current due time and reason for a recalculation.QUEUE-005Measured times. First-response and resolution measures are stored as business and calendar elapsed time and shown with their cycle. Reopening never overwrites a recorded first response.
AUTO 7 clauses
AUTO-001Rule lifecycle. A rule is Draft, Active, or Paused and has a name, ordered conditions and actions, creator, latest editor, version, and run count. Draft and Paused rules process no new events.AUTO-002Allowed actions. A rule can react to ticket creation, requester message, ticket field or status change, or one scheduled elapsed-time condition. It may apply a tag, set priority, assign an eligible group or agent, set a pending reason, send an internal notification, or apply a macro draft. It cannot send a public reply, complete a ticket, change a requester record, or invoke an external mutation. Policy:automation.action-allowlist.v1; default: the listed actions only.AUTO-003Order and audit. Active rules evaluate in visible order against one immutable triggering revision. Each run records matching conditions and each applied, skipped, or failed action.AUTO-004Idempotency and loops. A rule run is unique by rule version, ticket, triggering event or scheduled window, and action. An evaluation chain evaluates each active rule version at most once; duplicate events and scheduler runs repeat no effects.AUTO-005Concurrent changes and failure. A rule rechecks its conditions and ticket revision before mutation. A conflict is a visible skipped run. A failed action is visible with rule, ticket, attempted action, and error; a retry reuses its idempotency key.AUTO-006Rule authorisation. Only an Administrator may activate, pause, or change a rule's owner-visible scope. A rule cannot act on a ticket, group, form, or field its owner is not authorised to configure.AUTO-007Reviewed recovery. A retried failed rule run uses the original triggering revision and idempotency keys, reports any now-stale condition, and never replays an action that already succeeded.
NOTIFY 4 clauses
NOTIFY-001Accountable ticket updates. New unassigned tickets notify every eligible Agent; direct assignment notifies the new assignee or every eligible member of the assigned group; self-assignment sends nothing. Requester follow-up, at-risk, breach, and solved notifications go to followers, or to the assignee then eligible Administrators if there are no followers. An at-risk and a breach notification occur at most once each per service cycle.NOTIFY-002Coalescing and quiet hours. Repeated requester-follow-up events coalesce to one notification until an assigned agent opens the ticket; repeated event categories use their named service-cycle or open-cycle boundary. Policy:ticket.quiet-hours.v1; default: quiet hours defer non-urgent notifications while urgent and breached work bypasses them. Intake, service clocks, and other recipients are unaffected.NOTIFY-003No mail loops. Notifications use a configured no-reply sender that is not a support destination. Mail to that address creates or reopens no ticket and triggers no automation. Automatic acknowledgements are ticket mail under MAIL-014, not notifications.NOTIFY-004Failure reaches a person. A public-message delivery failure, automation failure, notification failure, or configuration/security failure is visible on the ticket or settings record and is delivered to the initiating agent, or every active Administrator when there is no initiating agent. This responsible-failure notification cannot be muted and never blocks or rolls back its causing event.
CSAT 3 clauses
CSAT-001Survey request. A solved ticket with a customer-visible accepted reply can queue one signed satisfaction request for that solve cycle. Policy:csat.request.v1; default: one email 24 hours after the solve. No survey is sent to a blocked requester, and reopening cancels an unsent request.CSAT-002Survey response. The single-use public link accepts one whole-number rating from one to five with an optional comment, expires after 30 days, exposes no unrelated ticket data, and never creates or reopens a ticket.CSAT-003Survey history. A result shows on the ticket and customer record with its solve cycle and time. A later cycle makes a new request and never overwrites a prior result.
INSIGHT 8 clauses
INSIGHT-001Operational dashboards. Analytics provides prebuilt dashboards for ticket volume and status, first-response and resolution duration, service-target outcomes, satisfaction score and response rate, assignment and group workload, and channel mix.INSIGHT-002Dataset and filters. Every report states its period, timezone, selected view or filters, ticket states, denominator, freshness time, and comparison period. It can filter by assignee, group, type, priority, tag, form, channel, custom field, and target state.INSIGHT-003Report builder. An authorised user can create, edit, save, share, and retire a report using documented ticket, customer, satisfaction, and service-target fields. A report exposes the tickets behind an aggregate only to viewers authorised for those tickets.INSIGHT-004Formatting and export. Dashboard and report users can choose supported chart and table formatting. An export contains the complete durable result for current filters and period with metric definitions, rather than only the rendered page.INSIGHT-005Freshness and correctness. Ticket, service-target, and satisfaction analytics reflect committed mutations within five minutes at the stated limits. A panel shows its last successful refresh and a stale or failed state; no cached result is represented as current.INSIGHT-006Operational export. An agent can export the complete durable current result of an authorised view, queue, dashboard, or report, including selected filters, period, and metric definitions. This convenience export does not replace DATA-001.INSIGHT-007Merge accounting. A merged source remains auditable and searchable but is excluded from live backlog, created, solved, and service-target totals. Its source conversation entries remain visible through canonical transclusion without double-counting the canonical case.INSIGHT-008Explainable drivers. Each classified volume, satisfaction, or service-target aggregate exposes its contributing tag or configured classification, stated denominator, and authorised ticket drill-down. Unclassified eligible tickets appear asOther; the displayed drivers, Other, and excluded denominator reconcile to the reported total.
DATA 3 clauses
DATA-001Portable export. Lily's complete export includes tickets, cases, conversations, messages, attachments, customers, organisations, forms, tags, views, macros, service cycles, automations and runs, satisfaction records, settings, article versions, record links, notifications, and audit entries, with original attachments. It contains no secret and follows baseline data guarantees.DATA-002Data boundaries. Export, retention, deletion, and erasure identify locally owned data and optional-adapter references. Lily does not claim to update, delete, export, or erase a provider record unless the configured adapter returned a confirmed result for that operation.DATA-003Zendesk importer. An Administrator can use the documented importer with an administrator-provided Zendesk export into an empty Lily installation. It validates mappings before mutation and offers dry run. It imports numbered tickets, requesters, messages, original attachments, tags, forms, groups, users, status history, merge history, and available metadata, with a per-record outcome and one import audit record. Each source object has a preserved source ID and a Lily ID; source ticket numbers are retained only when unused, otherwise Lily allocates the next permanent number and records the source-number mapping. Existing source IDs make reruns idempotent. Imported merge and status history are retained as source history; unsupported data receives a per-record outcome without fabrication. Stage 2 must prove this with a real export; no Freshdesk importer is committed.
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 run exportproduces every record and attachment;pnpm run 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 Lily 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.





