An agent harness built into the runtime. Shipped as one binary.
Build the app.
Put the agent inside.
Luca is a single binary for building apps with operators inside. An operator is an assistant: a prompt with tool calls, running in your process. It is wired to the same modules and capabilities that power your app, so it can read the same data and take the same actions. It answers through the doors you build: an endpoint, a socket, a phone line. You compile the app and its operators into one binary for macOS or Linux. Your software ships with someone on call.
Why put an agent inside the app?
Claude Code, Codex, and Hermes become functions. Your supervisor decides who writes, who reviews, and when the work is done.
An assistant inside the app reads the logs, restarts a process, and asks a coding agent for a patch. Then it runs the tests.
Phone, text, or Telegram. Ask the app for its status. The assistant reads the real data and answers.
An assistant with the Postgres feature and a prompt that names the tables. The CEO texts “signups today?” and gets a number, not a dashboard.
Build the
application.
Start with the parts a normal app has. An HTTP API from the files in endpoints/. A WebSocket server for live data. A static server for your site. Commands for the terminal. Shared state and events connect all of them.
Users sign up on the site. The API writes each signup to Postgres. The socket pushes the new count to the dashboard.
const api = container.server('express', { static: 'public' }) // endpoints/ mount themselves
const live = container.server('websocket', { json: true })
container.on('signup', (user) => live.broadcast({ type: 'signup', user }))
Add the features
the app uses.
Features do the work: Postgres, SQLite, a Markdown database, SSH, git, Docker, a scheduler. Your app uses them. Your assistants will use the same ones. Each feature has typed tools, and it can explain itself to a model.
The signups live in a Postgres table. The runbooks live in a folder of Markdown. The health check runs every five minutes on the scheduler.
const db = container.feature('postgres', { url: process.env.DATABASE_URL, readOnly: true })
const runbooks = container.feature('contentDb', { rootPath: './runbooks' })
container.feature('scheduler').every('5m', checkHealth)
Wire in
the assistants.
An assistant is a folder with a prompt, typed tools, and hooks. Give it a job and the features it needs. It runs inside your app, with the same state and the same events. It is a part of the product, not a chat window next to it.
Its prompt says which tables hold signups and performance. Give it the read-only Postgres feature. Now it can answer “How many signups today?” with a real query.
const ops = container.feature('assistant', {
folder: 'assistants/ops', // CORE.md names the tables: users, metrics.requests
})
ops.use(db)
ops.use(runbooks)
await ops.start()
Give it a door
for each caller.
People and other agents reach the assistant through what you build. An /admin endpoint for the dashboard. A phone number for a call or a text. Telegram. An MCP tool for your coding agents. A socket for another process. Same assistant, same answer, at every door.
The CEO calls or texts the number and asks how many signups the app had. The ops assistant queries Postgres and answers. No engineer wakes up.
const line = container.feature('telnyxConnector', {
assistant: ops, phoneNumber: '+13125550142',
allowedCallers: [process.env.CEO_PHONE],
})
await line.start() // calls and texts reach the ops assistant
Let it repair
the app.
Give an assistant the VM and it runs TypeScript inside the live app. It reads logs, restarts a process, runs the tests, and asks Claude Code or Codex for a patch. It can write a new assistant, test it, and roll back a bad change. You decide how much it may do.
The scheduler calls the ops assistant. It reads the error, finds the runbook, restarts the worker, and confirms the check passes. If code must change, it delegates the patch and verifies the tests.
ops.use(container.feature('processManager'))
ops.use(container.feature('vm')) // evalCode: live TypeScript in this process
container.addContext('coder', container.feature('claudeCode', { cwd: container.cwd }))
const checkHealth = () => ops.ask('Run the health check. Repair what fails. Report.')
Ship it as
one binary.
Compile the app, the features, and the assistants into one file. Build for macOS and Linux. The people who run it do not install Luca, Bun, or node_modules. The binary can still describe itself.
The ops team runs one file. It starts the API, the socket, the site, the phone line, and the assistants.
luca bundle signup-app --targets darwin-arm64,linux-x64 --builtins eval,describe
./dist/signup-app-linux-x64 start # api + socket + site + phone + assistants
One app. One binary.
An operator inside.
Most agents are clients of your software. A Luca assistant is a part of it. The features give it hands. The endpoints, sockets, and phone line give it doors. The VM lets it repair and extend the app. Start with one job. Add the next one when you need it.
Start from
a working pattern.
Six harnesses from the same story. Each one is code you can copy into a Luca project. Pick the one closest to your job. Change the prompt, the features, and the doors. Ship it.
Six starting points. Your combination comes next.
TypeScript / Luca runtimeGive the CEO
a phone number.
One assistant. A read-only Postgres feature. A prompt that names the signup and performance tables. A phone number that only the CEO can use. Call it or text it.
Line: Telnyx voice + SMS
- postgresRead-only SQL tools
- assistantPrompt that names the tables
- telnyxConnectorCalls and texts
- allowedCallersOnly the CEO gets through
import container from 'luca'
const db = container.feature('postgres', {
url: process.env.DATABASE_URL!, readOnly: true,
})
const ops = container.feature('assistant', {
systemPrompt: `You report on the signup app.
Signups are rows in public.users (created_at).
Latency and errors are in metrics.requests.
Answer with one number and one sentence.
Never read or repeat personal data.`,
})
ops.use(db)
await ops.start()
const line = container.feature('telnyxConnector', {
assistant: ops,
phoneNumber: '+13125550142',
greeting: 'Signup app. What do you want to know?',
allowedCallers: [process.env.CEO_PHONE!],
callerPolicy: 'screen',
})
await line.start()
// The CEO texts "signups today?" and gets a number back.
No npm install.
No supply chain to trust.
Luca is a complete system. The runtime, the features, the clients, and the servers are already inside the binary. Your project is a folder of TypeScript. You do not run npm install. Nothing downloads code into your app at build time or at run time.
Every module in Luca is chosen, reviewed, and checked for security before it ships. You get one audited set, not a tree of unknown packages.
There is no package list to attack. A coding agent cannot pull in a malicious package by mistake, because it does not install packages at all.
The binary you ship is the binary you built. Check one hash. Your team and your customers run it without a package manager.
Hand Luca to Claude Code, Codex, or Hermes. It learns the runtime with luca describe and builds apps that are safe by construction, with no supply chain to expose.
One binary in.
One binary out.
Luca is the tool you install. The tool you ship is yours. Your commands, your endpoints, your features, and your assistants compile with the runtime into one file. Give your team a signup app with an operator inside, and give the CEO a phone number. Both come from the same file.
Build for macOS or Linux with Bun on the build machine. The people who run it do not install Luca, Bun, or node_modules. They bring their own model provider and services. Keep eval and describe in the build, and the binary can still explain itself. An assistant with the VM can run this step too and ship a new version of itself.
# From your Luca project
luca bundle signup-app \
--targets darwin-arm64,linux-x64 \
--builtins eval,describe
# API, socket, site, phone line, and assistants inside
./dist/signup-app-linux-x64 start
./dist/signup-app-linux-x64 chat ops
Build the app.
Put the agent inside.
Install one binary. Build your app. Ship your own binary.
curl -fsSL https://luca-js.soederpop.com/install.sh | bash
luca bootstrap signup-app
cd signup-app && luca chat