SEIF Docs

Data & go live

Data & go live connects an agent to the data it should work with and puts it online:

  • Data: a Postgres database (directly or through your own server), a SQLite file, a Google Sheet or a Google Doc.
  • Online: a chat link anyone can open, WhatsApp through your Evolution API, a chat bubble for your website and an API for other apps.
  • Better every day: try it in the app, see what it could not answer, teach it in one step, and send scheduled answers.

It is built for people who do not write code. Each step is a form with a Test button, and nothing is saved until Save.

What it writes is plain project files:

  • connections/<name>.yaml and launch.yaml, which the Lab, the World, tests and Git all see.
  • Passwords and keys go to this computer's credential vault and never enter a project file.

Connect your data

Open it from:

  • the World: 🔌 Data & go live in the top bar;
  • the Lab: the plug icon in the activity rail, or Connect data & go live in the command palette.

The guided path

A strip at the top shows five steps: Connect data → Choose a brain → Try it → Go live → Share. Each step is checked from what is true in the project (a working connection, a stored key, a try in the log, the agent running, a link or key shared), not from clicks. Next: says what to do; clicking a step takes you there.

What makes it different from a workflow tool

A workflow tool hands an AI node whatever the previous node produced. Here, every answer goes through SEIF's escalation of options. For each message, the engine resolves:

  • what the agent has in hand;
  • which doors it may open by itself;
  • which lookups it may run, read-only.

Out-of-view and sealed material never reaches the model.

The same project shows that menu in the World before you go live. Each conversation is written down with its "why":

  • the pieces in hand;
  • the doors it opened;
  • the lookups it ran and how many rows came back.

People chatting can see it too, under Why this answer?.

Connect your data

KindHow you connectWhat the agent can do
PostgreSQLPaste a postgres:// link or fill the fields. Optionally go through my server (SSH).Look up tables while answering. Learn small tables as areas.
SQLiteChoose the file.Same as Postgres.
Google SheetsPaste the link of the tab. Works with Anyone with the link, or private through a service account.Look up rows. Learn a tab as an area.
Google DocsPaste the link. Shared by link or through a service account.Learn it: each heading becomes a piece.
WhatsAppEvolution API address, instance and API key.Answer people who write to that number.

MySQL and MariaDB are not supported yet. Postgres and SQLite work today.

A database on your server (SSH)

Many databases only answer inside their server. For example, a Postgres container on a Docker network with no published port, like the carimbó database on seif-prod-arm.

To reach one:

  1. Type the server name you use with ssh. Known aliases from ~/.ssh/config are offered as chips.
  2. Press Find databases.

A database on a server, found through SSH

SEIF runs your own ssh with your keys and agent, and never prompts:

  • Find databases lists Docker database containers and their addresses on the server, plus listeners on the usual ports. Click one to fill the address.
  • A container name in a pasted link (for example carimbo-postgres) is turned into that container's address on the server.
  • Connecting opens a local tunnel (ssh -N -L 127.0.0.1:<free port>:<address>:<port> <server>) and closes it afterwards.
  • SSH keys and passwords are never stored.
  • If ssh <server> asks for a password in a terminal, it fails here with that explanation.

Safety of every connection

The agent never writes SQL:

  • Each lookup is a fixed, parameterized query over the columns you ticked.
  • The agent fills in only three things: words to search, exact matches on those columns, and a row limit.
  • Identifiers are quoted. Values are parameters.

Every Postgres session:

  • is opened with default_transaction_read_only=on;
  • has an 8-second statement timeout.

SQLite files are opened read-only.

Credential columns are never given to an agent:

  • A column whose name looks like a credential (password_hash, token, secret, api_key, session…) is shown locked and cannot be ticked.
  • A connection file that lists such a column is refused.

Cell values are redacted for credential patterns before the model sees them.

Credentials are never in project files:

  • The form stores the password, API key or service-account key in the vault.
  • The file keeps only a reference, for example password: vault:cp-….carimbo.
  • On a server, use env:NAME references instead.

A stored credential is sent only where it was saved for:

  • Database passwords: the database address, and the SSH server when there is one.
  • WhatsApp keys: the Evolution server.
  • Model keys: the provider and its address.

A project file that points a stored reference at another address is refused before anything is sent. This holds even for a project someone shared with you. Changing an address in the form asks for the credential again.

A SQLite file outside the project folder is used for lookups and sync only after you chose it on this computer with Save. A shared project cannot quietly expose another database file on your disk.

For a production database, create a read-only role that sees only what the agent may use. For example, on carimbó's Postgres:

CREATE ROLE seif_reader LOGIN PASSWORD '…';
GRANT CONNECT ON DATABASE carimbo TO seif_reader;
GRANT USAGE ON SCHEMA public TO seif_reader;
GRANT SELECT ON articles TO seif_reader;  -- the news archive only: no accounts, sessions or payments

What the agent may do with each table

What the live agent may do is the agent's own list of capabilities, the same one the Team and the Agent Workspace use (One agent system): connected data (the lookups below, which every agent has until you change it in the Agent Workspace's Capabilities → Built in) and the Tool contracts its knowledge settings allow, connected to a system. A Tool contract that changes data never runs from a conversation by itself: it waits in Needs you for your approval, exactly as asked.

After Test connection, every table or tab gets three choices.

Choosing what the agent may do

⚡ Look up while answering

This is within reach: the agent gets a tool such as lookup_shop_orders that it may call when a question needs it.

  • Columns: the ones you ticked; you can search a helper column, like a normalized search_text, without showing it.
  • Rows: at most 10 by default and never more than 50, newest first when there is a date column.
  • Search: every word must appear in one of the text columns. Accents and case do not matter.

The details page has Try lookup. It shows exactly the rows the agent would receive.

📚 Learn it

The rows, or a document's sections, are copied into a snapshot and become pieces of an area. They resolve like any other knowledge:

  • The agent gets the pieces that match the question.
  • In the World they are crystals you can inspect, expect or guard.

How the copy works:

  • Size: at most 200 rows or sections; larger tables are better as lookups.
  • Location: the snapshot is stored in .seif/connections/, which is ignored by Git and stays on this computer.
  • Refresh: Sync now brings a fresh copy, and a live agent refreshes every refreshMinutes (30 by default).

A new area stays out of view until you allow it. This is the same consent rule as for a new knowledge file. The tick Let the agent use the areas I add adds a retrieve rule to the agent's context.yaml.

Not used

The agent never sees the table.

The files

connections/shop.yaml (written by the form, editable in the Lab):

kind: sqlite
name: Shop
file: shop.db
use:
  - id: orders
    mode: lookup
    label: orders
    table: orders
    columns: [id, customer, status, total, created_at]
    search: [customer, status]
    order: { column: created_at, direction: desc }
    limit: 5
  - id: faq
    mode: knowledge
    label: Help center FAQ
    table: faq
    columns: [question, answer]
    title: question
    layer: help-center-faq

launch.yaml:

agent: support-agent
model: { provider: anthropic, model: claude-opus-5-5, key: vault:model.anthropic, effort: medium }
chat:
  title: Lumen help
  greeting: Hi! Ask me anything.
  suggestions: [Where is my order?, How do refunds work?]
  showSources: false     # default; true shows sources under each chat answer (debug/governance, not for end users)
  language: pt-BR        # optional; otherwise each visitor's browser language (en, pt, es)
whatsapp: { connection: whatsapp }
refreshMinutes: 30

The credential vault

The vault lives in the Workstation's per-user folder (…/SEIF/ContextWorkstation/vault/):

  • Values are encrypted with AES-256-GCM.
  • The key sits next to them, readable only by you.

What this protects against:

  • credentials leaking through Git, exports or project backups.

What it does not protect against:

  • someone who can already read files as your user.

Go live

Live: links and conversations

  1. Choose a brain.
ChoiceWhat it uses
ClaudeThe official Anthropic SDK; Claude Opus 5.5 by default, with Sonnet 5.5 and Haiku 4.5 to choose from.
OpenAI-compatibleAny compatible endpoint: OpenAI, OpenRouter, Groq, LM Studio…
Ollama (local)Lists the models Ollama has pulled.
Installed CLIClaude Code, Kiro CLI or Codex on this computer, with its own saved login: no API key.
No AI (rehearsal)No model at all.

Details:

  • Claude: on Opus and Sonnet, a declined request falls back to another model on Anthropic's side. Effort is medium, and launch.yaml can change it.
  • API keys: a key is stored once per provider and shared by your projects.
  • Installed CLI: sign the client in once in Terminal (claude auth login, kiro-cli login or codex login). Leave the model empty for the client's default. The client's own tools and MCP servers stay off: each tool call comes back to SEIF to run, with the same approvals. Usage counts against that account's limits and has no list price, so the team marks it ▲ and bounds it by runs per day. launch.yaml keeps only the client and the model (provider: subscription-cli, engine: kiro); the executable is found in PATH, ~/.local/bin, ~/.npm-global/bin, /opt/homebrew/bin or /usr/local/bin, never read from the file. Installed clients run only in the desktop app.
  • Test brain saves and sends one short request, so a missing login or an unknown model shows up here.
  • Rehearsal: answers show what the agent would work from. Use it to try the whole path (link, WhatsApp, lookups) before choosing a model.
  • The brain chosen here is also the development model of the Agent Workspace and the Team's brain: one choice.
  • Choose the version (when the agent has releases). Working draft answers with the agent's files as they are now; a release (made in the Agent Workspace) answers exactly as it was tested: its instructions, knowledge and capabilities are pinned. launch.yaml keeps it as release: guru-v2, and every answer records which version answered.
  • Set the chat page. Title, greeting, suggested questions and language.
  • Pick WhatsApp. If you connected it, choose it here.
  • Choose who can reach it.
  • Public link: anyone with it can chat. This needs cloudflared, for example brew install cloudflared. SEIF starts a quick tunnel and shows the https://….trycloudflare.com link; without cloudflared it says how to install it.
  • Also on my network: others on your Wi-Fi can open it.
  • Press ▶ Go live at the top of the panel. The links appear with Open and Copy, and conversations appear as they happen. Without an AI brain the status reads Live · practice answers.

While it runs:

  • The agent keeps running while you edit in the Lab or the World.
  • Save settings and connection changes reload it without changing the links.
  • Closing the app stops it.

The chat page

The public chat page on a phone

Screenshot of the carimbó example against a local test copy of the archive.

  • Real: the data and the lookup.
  • Scripted: the model was a test double, so the image does not depend on a paid key.

What the page offers:

  • Phone-first: light and dark themes, suggestions people can tap, and Why this answer? under each reply.
  • Languages: English, Portuguese and Spanish, chosen from chat.language or the visitor's browser.

How it is protected:

  • Messages: at most 2,000 characters, and 30 per address every five minutes. The same limit applies to each WhatsApp number.
  • Requests: cross-site requests are refused, and a strict content security policy applies.
  • Content: text is always inserted as text, never as HTML.

Each browser has its own conversation. The last 12 messages are remembered while the agent runs.

WhatsApp (Evolution API)

Add a WhatsApp connection:

  • the Evolution address;
  • the instance;
  • the API key;
  • who can talk: anyone, or only listed numbers.

Check connection shows whether the number is connected. If it is not, it shows the QR code to scan in WhatsApp → Linked devices.

When the agent goes live with a public link, SEIF points the instance's webhook at it: POST /webhook/set/<instance> with MESSAGES_UPSERT. A secret path authenticates it.

Each incoming text message is answered with Evolution's sendText:

  • Messages from the number itself, groups, broadcasts and repeated deliveries are ignored.
  • LID addresses (Evolution v2.3+) are handled with the same routing used by the existing WhatsApp channel, which came from saas-factory.
  • Media messages are not answered in this version.
  • Markdown becomes WhatsApp formatting.
  • Phone numbers are not written to the conversation log; it keeps a hash only.

The record of every answer

.seif/launch/turns-<date>.jsonl (Git-ignored, redacted) keeps one line per answer:

  • channel, question, answer, model, time and status;
  • the pieces in hand;
  • the doors opened;
  • the lookups run, with their row counts.

The Conversations panel shows the same.

Try it

Try it in the app

The 💬 Try it tab is a chat with the brain chosen in Go live, inside the app. It does not need the agent to be live or a link. Ask what your customers would ask. The ideas above the box come from the suggested questions of the chat page.

Under each reply, chips say what it used:

  • 📚 a piece the agent had in hand (hover for where it is);
  • 🚪 a door it opened by itself;
  • ⚡ a lookup it ran, with the rows it found.

When the agent cannot answer from what it has, it says so instead of guessing. The reply says It could not answer: and what was missing, and Teach the answer → takes you to Improve with the question filled in.

Tries are written to the conversation log as channel try. Improve counts them apart, so your own tests do not inflate the numbers of real conversations.

Improve from real conversations

Improve

The 📈 Improve tab reads the conversation log of the last 14 days (link, WhatsApp, other apps and routines) and turns it into improvements you review:

  • Numbers: answers, how many could not be answered, open gaps and the average time to answer. Answers per day are drawn as bars, with the answers it could not give stacked on top.
  • Questions it could not answer. The agent has a cannot_answer tool and is told to use it instead of inventing. Each such question appears with how many times it was asked. Write the answer, choose the topic (its themed knowledge area) and press Teach the answer. SEIF:
  • writes knowledge/<topic>/<topic>.md, adding the answer as a ## section with the question kept inline;
  • gives the area a layer rule, so the agent has it in hand;
  • writes tests/taught-<question>.ctx.md, a check that the question keeps reaching that piece;
  • runs the check. A taught question leaves the list.
  • Doors it keeps opening. A door opened in at least 3 answers and 20% of them is suggested to be kept in hand. Keep in hand… shows the change to the layer rule as a draft.
  • Lookups that find nothing. A lookup that came back empty or failed in half of 3+ calls is shown with Open connection, to fix its search columns.
  • Recent conversations. Keep answering like this… on a good answer lets you tick the pieces it must keep getting and drafts a check, tests/kept-*.ctx.md.

Drafts appear as a card that says in one sentence what will change; Show the file opens the exact file. Accept applies them through the Lab, so the same review, Git history and tests apply. Not now discards them.

Routines

Routines

A routine asks the agent a question at a set time and sends the answer. For example, "List today's open orders" at 08:00 on weekdays, to the shop's WhatsApp and a Slack channel.

  • When: a time (HH:MM) and the days. Times are in the project's time zone, which the app sets from this computer when you save.
  • Where: WhatsApp numbers (through the WhatsApp connection chosen in Go live) and/or one webhook link (Slack, Discord, n8n, Zapier…). The webhook receives {"text", "content", "routine", "at"}.
  • Preview runs it now and shows the answer without sending anything. Send now in the list sends it.
  • Routines run while the agent is live, at most once per day each; the last run is remembered across restarts. If the computer was asleep (or daylight saving skipped the time), a routine still runs within the hour after. A routine saved after its time today starts tomorrow.

Routines are saved in launch.yaml:

timezone: America/Sao_Paulo
routines:
  - id: open-orders-at-8
    name: Open orders at 8
    at: "08:00"
    days: [mon, tue, wed, thu, fri]
    prompt: List today's open orders.
    send:
      whatsapp: ["5511999990000"]
      webhook: vault:routine-1a2b3c4d-open-orders-at-8

A webhook link works like a password: whoever has it can post to your channel. So the app keeps it in this computer's vault and launch.yaml only holds a vault: reference.

A launch.yaml can also arrive from someone else through Git. A number or webhook is only sent to after you saved that routine in Routines on this computer: saving one routine never confirms another. Until then the routine shows Review and confirm…, and a run says Not confirmed on this computer and sends nothing.

Share: your site and other apps

Share

The 🔗 Share card in Go live appears once the agent is live.

On your website. Paste one line before </body>, on WordPress, Wix, Shopify or plain HTML:

<script src="https://YOUR-LINK/widget.js" data-label="Ask us" async></script>

A chat bubble opens the agent in a panel (/embed). data-color changes the bubble color.

Only the sites you list may show it, so nobody can put your agent (and your model bill) on a site of theirs. In the Share card, type your site's address and press Allow; the snippet appears after that. The list is kept in launch.yaml:

chat:
  sites: [https://www.example.com]

Sites on the internet need the Public link (or --public-url); the card says so when the snippet still points to this computer.

Other apps (n8n, Zapier, Make, your backend). Create API key shows a seif_live_… key once. Only its hash is kept, on this computer (next to the vault, never in the project), so a shared project cannot bring keys of its own. Revoke stops a key at once. An agent can have up to 20 keys; old ones are never dropped silently.

curl -s https://YOUR-LINK/api/v1/answer \
  -H "Authorization: Bearer seif_live_…" \
  -H "Content-Type: application/json" \
  -d '{"message":"Where is my order?","session":"customer-42"}'

The answer is {"reply", "status", "gap", "why"}. why always comes with the answer here: the API answers the integrator's system (which holds the key), not the end user, so chat.showSources only affects the chat page. The same session keeps the conversation going. Each key is limited like a chat visitor (30 messages every five minutes). In n8n, this is an HTTP Request node with Header Auth.

examples/carimbo-news-desk is ready for the carimbó database on seif-prod-arm. Its README has the full steps.

  1. On the VM, create the read-only role above.
  2. Open the example. In Data & go live, select carimbó (produção) and press Edit.
  3. Type the role's password and press Test connection. The SSH tunnel to carimbo-postgres opens with your keys.
  4. Keep articles as a lookup and Save. Try lookup with eleitoral shows real headlines.
  5. In Go live, choose Claude, paste the key, tick Public link and press ▶ Go live.
  6. For WhatsApp:
  7. Add a WhatsApp connection with your Evolution server (the one from saas-factory), its instance and API key.
  8. Choose it in Go live.
  9. Go live again, so the webhook is set to the new public link.

Running it on a server

The live agent is one Node process:

runtime/node runtime/engine/launch.mjs --project /path/to/project --port 8080 --host 0.0.0.0 --public-url https://help.example.com

On a server there is no desktop vault, so use env: references:

  • password: env:CARIMBO_DB_PASSWORD in the connection;
  • key: env:ANTHROPIC_API_KEY in launch.yaml.

--public-url is the address people use, for example a named Cloudflare Tunnel like carimbó's. WhatsApp's webhook is set to that address.

The process prints one JSON event per line:

  • listening
  • public
  • whatsapp
  • sync
  • turn
  • error

It stops when its standard input closes or on SIGTERM. Send reload on standard input to re-read launch.yaml and connections.

Not in this version

  • MySQL and MariaDB.
  • Agent actions that write to your data, such as appending a row or inserting a record. Lookups are read-only by design.
  • Routines while the agent is not live: they run inside the live agent.
  • WhatsApp media.
  • Sign-in on the public chat: anyone with the link can chat, within the rate limit.
  • Human handoff. The Agent Factory has it.
  • Conversation memory across restarts.

Proof

bash scripts/prove-connect.sh runs the engine tests and the native screen tests. It writes the screenshots in evidence/connect/.

The engine tests cover:

  • Vault: encryption, and refusing plain credentials in files.
  • Credential binding: stored keys are never sent to an address a project file changed, and database files outside the project need local approval.
  • SQLite: lookup and learned area; credential columns refused; injection-safe input; accent-insensitive search; every word of a search compared with every searchable column.
  • Postgres: a real server, when one can be started, reached through an SSH stand-in. Only granted tables are visible, the session is read-only, and a container name resolves to its address.
  • Google: Sheets and Docs by link and by service account (JWT signed and verified), plus the "share it" message for private files.
  • Live agent: the chat link, WhatsApp webhook routing, Claude through the official SDK with doors, the OpenAI-compatible path with lookups, rehearsal, the public link through cloudflared, and the turn log.
  • Learning: a question the agent cannot answer becomes a gap; teaching it writes a piece, a rule and a check that passes; doors opened often and empty lookups become reviewed drafts; a good answer becomes a check.
  • Routines: the schedule in a time zone, once per day, catching up within the hour (sleep, daylight saving), previews of the unsaved form that send nothing, destinations refused until that routine is saved on this computer (saving another one never confirms it), the webhook kept in the vault, then WhatsApp and a webhook.
  • Sharing: API keys (hashed, outside the project, revocable, at most 20, rate limited), the embeddable page shown only by listed sites, and one conversation per browser, cookie or session.

The native screen tests cover:

  • connecting a database in plain steps;
  • trying a lookup;
  • going live in rehearsal and answering on the link;
  • finding a database on a server through SSH;
  • the guided path end to end, with a scripted OpenAI-compatible model: choose a brain, try it (a lookup and a gap), go live, answer four visitors, teach the gap, keep a good answer as a check, schedule a routine, share the widget and call the API with a new key;
  • in the World, ✦ Answer with AI giving a real answer and lighting the door it opened.