Concepts¶
Everything you do is recorded as an event. Your files are artifacts. What you want is an intent, and how to do it is knowhow. An app gives that a UI. A trigger runs a script, or starts the assistant or a coding agent, on a schedule or when an event happens. A webhook lets an outside service set off a trigger.
Every chat, trigger run and coding-agent run is a thread. The proxy connects your accounts to the assistant, your apps and your scripts. A plugin bundles the pieces so you can share them.
Events and artifacts¶
Events are the immutable record of what happened, and the source of truth. Artifacts are your durable, git-tracked files.
Event¶
A past-tense fact about something that happened in the workspace, named in the past tense even when transient. Persisted events are written to the events table, replay, drive projections and match triggers. Transient events go over SSE only and never reach projections or the trigger matcher. Subtypes: thread lifecycle events (MessageReceived, ResponseGenerated, …), system events (notifications, preferences, …), and domain events. There is no command concept: anything imperative becomes a request event (AppUiRefreshRequested, not RefreshAppUI), and a subscriber chooses whether to act.
Artifact¶
A user-owned file under data/artifacts/. Git-tracked, never auto-deleted. Includes notes, imported API data, project folders, screenshots, generated images. The durable counterpart to ephemeral runtime state under .lucidos/.
See also: system-knowhow/best-practices.md § artifacts/.
Because events are the authority, these always hold:
Key Invariants¶
- Events are immutable
- Git commits are consequences, not causes
- No hidden state or silent decisions
- Replay reconstructs truth, not creativity
Intent, knowhow, and scripts¶
Lucidos keeps three things apart: what you want (stable, in your words), how to do it (technical, evolving), and the code that does it.
Three Content Types¶
| Type | Stability | Who maintains | Example |
|---|---|---|---|
| Intent | Stable — changes when the user's needs change | User | "Find relevant jobs, store them, notify me of new ones and deadlines" |
| Knowhow | Evolves — refined every time Lucidos learns something new | Lucidos | "Use .product-card img selector, vendor CDN requires base64 conversion" |
| Script | Changes when tools or APIs change | Either | download_images.py, validate_images.py |
Intent vs Knowhow¶
The intent describes what the user wants — written in user terms, like what you'd tell a competent assistant. The knowhow describes how to do it well — technical details that Lucidos accumulates over time.
Test: "Would a non-technical person understand this file?" - Yes → it's an intent - No → it's knowhow
Example: A product-watch intent says "find relevant listings for me, store them, notify me if there are new ones or upcoming deadlines." The knowhow explains how vendor logos are extracted, how prices are normalized, what CORS workarounds are needed. When Lucidos discovers a new quirk, it updates the knowhow — the intent stays the same.
Apps and triggers¶
An app is a UI you open repeatedly. A trigger runs work on a schedule or in response to an event.
App¶
A user-installed mini-application with its own UI (HTML/CSS/JS) at data/apps/<id>/, plus optional knowhow / intents / scripts / triggers. Chat is not per-app: every conversation is a regular chat thread. While an app is open in the panel-overlay slot, its manifest.json and discovered context flow into the Lucidos Agent's prompt. Quick edits use the agent's file tools; heavier edits spawn an app coding-agent thread. The app manifest is user-facing metadata; knowhow/ and intents/ are engine-facing context loaded while the app is active. Its interactive surface is the app UI.
An app folder has a kind: an ordinary app, listed in the apps panel, or a widget, shown in a thread and never listed.
See also: system-knowhow/building-an-app.md, docs/taxonomy.md § Apps.
Trigger¶
A workspace configuration that fires on a schedule (run.cron) or on one of its event subscriptions (on). The run takes one of two shapes:
- run.type: "intent": spawns a trigger thread whose LLM gets run.intent (the user's voice, non-technical prose) as a user message. It finds the knowhow it needs via load_knowhow at fire time; there is no per-trigger knowhow allowlist.
- run.type: "script": runs the script at run.path directly, no LLM. On event fires the engine sets TRIGGER_EVENT_TYPE / TRIGGER_EVENT_PAYLOAD / TRIGGER_EVENT_ID / TRIGGER_EVENT_THREAD_ID. So the script can branch deterministically and deep-link a notification to the originating event. Right for a deterministic transformation that needs no LLM judgement.
Lifecycle (both shapes): defined by TriggerCreated; each firing emits TriggerStarted then TriggerCompleted. The panel row shows its last-run status (OK / failed) beside the last-run time; there is no built-in run-history view. For more, ask the Lucidos Agent ("what has this trigger been finding?") or build an app on its event stream.
The row also shows the next runs: the next few fire times, merged across every cron expression. A cron that can never fire (0 0 9 31 2 *, Feb 31) is rejected at create and update, naming the offending fields. A trigger stored before that guard still loads, but wears a schedule error rather than the "No more runs" of a spent one-shot. Neither has a next run, but one never worked and the other finished its job.
See also: system-knowhow/triggers.md, docs/taxonomy.md § Triggers.
Once you create a trigger, it runs unattended. An intent trigger starts a trigger thread with every tool the assistant has. That thread can start sub-threads, or hand code work to a coding agent.
Webhooks¶
A webhook receives events from an outside service, and a trigger can react to them. It is the one surface a stranger can reach.
Webhook¶
An endpoint you point a third party at, so their service can tell Lucidos something happened. Each webhook emits exactly one domain event, which a trigger can then react to. Manage them at Settings > Webhooks, or with lucidos webhooks.
The event is pinned when you create the webhook, and no caller can change it. So an endpoint you gave GitHub only ever fires the event you chose, whatever GitHub posts. For several kinds of message from one sender, fire one event and discriminate in the trigger's condition on the sender's own fields.
Only you create one. No agent tool or app can, for the same reason an agent cannot grant itself a side-effect grant: a webhook opens a door, and an agent must not widen its own authority.
A delivery has to prove itself. An unsigned webhook carries a token, shown once at creation, that the sender returns as Authorization: Bearer <token>. Or it carries a signature configuration, as GitHub, Stripe and Slack sign the request body with a shared secret. Those senders attach no token, so a signed webhook gets none. The secret is a credential you save once and name here, never a copy beside the webhook.
The sender decides which side invents that secret, and the form follows. GitHub takes whatever secret you put in its webhook form, so Lucidos offers to generate one and shows it once for pasting. Slack and Stripe issue their own in their console, so you paste those in. Either way you may name an already saved credential instead.
A signature can be changed or removed without changing the URL, so a rotated secret or wrong signature header is fixed in place. A webhook carries exactly one of the two verifiers. Adding a signature drops the token; removing one mints a fresh token, shown once.
A delivery becomes an event shaped {summary, headers, payload}. The sender's body is under payload, so a trigger condition reads payload.action. Allow-listed request headers are under headers, read as headers.X-GitHub-Event.
A sender will resend the same delivery, and by default that emits the event again. GitHub retries a slow response and offers a Redeliver button; Stripe retries for days. Every arrival stays on the event log, so you can see how often a sender repeats. Switch on delivery deduping to count each delivery once.
Deliveries arrive on their own port, the hook socket, which answers webhook URLs and nothing else. That makes it the one surface safe to expose to the public internet with tailscale funnel.
See also: trigger, domain event, credential, delivery deduping, system-knowhow/lucidos-cli.md § lucidos webhooks.
Threads¶
A thread is one run of work. A chat, a trigger run and a coding-agent run are all threads in the same workspace. The assistant (the Lucidos Agent) can split a job into sub-threads that run in parallel, and each one reports back when it ends. It can also hand code work to a coding agent (Claude Code or Codex). The coding agent works in its own git worktree and proposes a change for you to review and Apply.
Sub-thread¶
Any descendant in the thread tree (transitive): a child thread or a grandchild alike. Say child thread for the direct relationship and sub-thread when depth doesn't matter.
Proxies¶
You connect a service once. After that, the assistant, your apps, your scripts and your triggers all call it through the proxy. The engine adds the key to each request, so an app never sees it.
Proxy¶
The engine's route to an outside service. You connect the service once, as an entry in data/config/apis.json: an API key, an OAuth sign-in, or a custom handshake or signer. The Lucidos Agent calls it with proxy_request, an app with lucidos.proxy(<name>), and a script with lucidos proxy <name>. A trigger reaches it through its thread or its script. The engine adds the credential to each request server-side, so an app never sees the key.
A builtin provider proxy reaches a model provider with no apis.json entry.
See also: system-knowhow/building-an-auth-handshake.md, system-knowhow/js-sdk.md § lucidos.proxy.
Plugins¶
A plugin bundles apps, triggers, knowhow and scripts that belong together. You install one from any git repo: a public GitHub repo to share with everyone, or a company repo to share with your coworkers.
Plugin¶
A bundle of installable workspace content shipped as one unit. Contains any of apps/, knowhow/, triggers/, scripts/, auth-modules/, themes/, fonts/, mirroring the top-level data/ directories. Its apps/ may hold reusable widgets the plugin owns. Defined by a plugin manifest at the root, beside an optional media/ folder of plugin media. Install merges the contents into the workspace's data/. Use a plugin when the pieces only make sense together (an app, its knowhow and its trigger); ship single files on their own.
See also: system-knowhow/plugins.md.
The prompt-first model¶
The prompt is the primary interface. You describe what you want, and Lucidos builds the data and the presentation together, live.
Live co-creation¶
The principle at the heart of Lucidos: you and the Lucidos Agent shape the whole living system, data and presentation together. You do it continuously and in place, with no build → deploy → observe gap. The Conversation and the Canvas are always live and a gesture apart: side by side on desktop, a swipe apart on mobile. The Canvas runs on the real workspace, since apps read live data through the SDK. So you research, build and iterate inside Lucidos in one motion, seeing real behavior at once. The Conversation↔Canvas back-and-forth is the surface of live co-creation; the depth is that one conversation reaches the entire stack.
Coming from other AI tools? The "skill" question¶
Other AI assistants often package "how to do X" as a skill. Lucidos splits a skill into these pieces:
| Where a "skill" elsewhere bundles… | In Lucidos it's a… |
|---|---|
| Instructions the agent follows for a task | Knowhow: how-to docs the Lucidos Agent writes, keeps up to date, and loads on demand |
| A reusable interface for the capability | App: a persistent UI under data/apps/<id>/ |
| Helper code the instructions call | Script |
| The whole capability shipped as one installable | Plugin: a bundle of apps + knowhow + triggers + scripts |
| "Do this automatically / when X happens" | Trigger |
Knowhow is the closest match to a skill, but you never invoke it by name. The agent matches your request against each knowhow file's description at runtime, and loads the file when it is relevant. A new knowhow file is available as soon as it exists. The agent writes one when it learns something new, and updates a file when it finds a quirk or a better approach. You can write and edit them too.