Skip to content

QUICKSTART · 15 MINUTES

Build a governed AI application

You are going to build a small AI application against your own API, in your own environment, and finish holding proof of exactly what it did.

Five acts. Get a runtime you control, meet the agent that does the work, hand it a job, point it at an API of yours, then watch the platform refuse something and verify the receipts for the run that worked.

Nothing here is a sandbox or a simulation. Every command below runs real work through the same authorization path a production run uses.

What you'll have at the end

An agent that runs on your machine, a plan that calls an AI model, a second plan that calls a real HTTP API through a credential the agent never sees, a refusal you triggered on purpose, and a signed receipt chain anyone can check.


Before you start

You need a terminal on macOS or Linux; Windows works inside WSL. Act 4 calls a real HTTP API, so have an API key ready. The example uses a public weather API, and signing up for a key takes about a minute.


Act 1 · Get a governed runtime

About 3 minutes.

Your agents run on your infrastructure. EKKA decides what is allowed to happen and records what did. It never holds your data, your credentials, or your model output. The thing you install below is where the work actually happens, and it is yours.

1 · Install the ekka CLI

curl -fsSL https://get.ekka.ai/install.sh | sh
ekka --version

One signed binary lands on your PATH. That same binary is the CLI you type and the Enclave you start in step 4. Re-running the install line upgrades in place.

2 · Sign in

ekka login --email [email protected]

We email you a link. Open it, confirm the code shown in your terminal, and you are signed in. No password to choose and none to lose. If the address is new, signing in creates the account.

3 · Create your organization

ekka org create <your-org-code>     # e.g. jane-labs, NOT literally "acme"

Pick a code that is yours: lowercase letters, digits and hyphens, starting with a letter, 2 to 63 characters. Codes are unique across all of EKKA, so a common word someone else already took will be refused.

The code you pick is your organization code. Everything you own belongs to it: Enclaves, gates, agents, grants, receipts.

Already invited to someone else's organization? Skip this step. You joined it when you signed in.

4 · Start your Enclave

ekka enclave create --name my-laptop
ekka enclave start <enclave-id>

The first start claims the Enclave for this machine and then runs it in the foreground. Leave it running and open a second terminal for everything below. Next time, plain ekka enclave start is enough.

On a server, do not leave it in a terminal

That is right for your laptop while you are learning, and wrong for a server: a process in a terminal does not come back after a reboot or a crash. See Running on a server for the five-minute systemd install.

Why the id is safe to share

The id names your Enclave. It does not unlock it. Starting one takes the id and a signed-in person, so someone holding only the id can do nothing with it. That is why an admin can create Enclaves and hand the ids out. The first start binds an Enclave to one machine, and a second machine trying the same id is refused.

The first start looks for Claude Code on this machine

If Claude Code is installed here, that first start records its path and your Enclave can offer it as a governed model. Nothing runs through it until you grant a model to a plan. The setting is optional: see Claude Code on this machine for the path it writes and how to turn it off.

Check where you stand:

ekka whoami

Act 1 done

You have a runtime under your own control. From here on, every command is checked against policy before it does anything, and recorded after.


Act 2 · Meet your agent

About 2 minutes.

Before you write anything, meet the thing that will run it.

An agent is the identity your work runs as. It is not a chat wrapper and it is not a prompt. It is a principal your organization owns, and it carries a declaration: the list of capabilities it may ever use. A plan is a job you hand an agent, and the job has to fit inside that list.

5 · See what can act in your organization

ekka agent list

Your organization already has one. Creating the org created its Core Agent:

  AGENT          NAME        SOURCE        PLANS
  core-979f755d  Core Agent  core (yours)      0

  what each may touch  ekka gate grant list

Look at the PLANS column: zero. The agent exists before any work exists, which is the shape worth remembering. The agent is the thing that exists and holds the permissions. A plan is a job you hand it. You never create an agent by hand; every plan you write belongs to this one unless you install another.

6 · Read what an agent declares

This is the part most platforms do not have. One command prints any agent's job description:

ekka agent show core-979f755d

Run it now and the declaration is empty, which is correct: an agent that has been asked to do nothing may do nothing. It fills in as you hand it work. After Act 3 the same command prints something like this:

  core-979f755d  v1.0.0

  DECLARED (major 1):
    llm.infer           [email protected]

The DECLARED block is what the agent asks for, with the plans that use each item beside it. An agent declares up front, as a list, and a plan that needs something outside the list is refused when you save it. The declaration is versioned, and the first number is the permission contract: same major, same permissions.

Reading it matters most when the agent is not yours. Anything published is in the catalog, and show works on those too, so you can read a declaration before you agree to it:

ekka agent catalog
ekka agent install <agent>

install prints that same declared list and then records that your organization agreed to that major version. If the publisher later widens what the agent asks for, they have to bump the major, and nothing crosses a major automatically: the agent pauses in your organization until one of your admins reviews the new list and approves it. You are never quietly upgraded into permissions you did not read.

Act 2 done

You have an employee, and you can read its job description before it does anything. Now give it a job.


Act 3 · Give it a job

About 3 minutes.

Your agent needs somewhere for the work to land. See which gates your organization can address:

ekka gate list

A gate is how work reaches the outside world: an AI model, a database, an API, the filesystem. The listing shows each gate's selector, what it can do, and the model ids or resources it advertises. Note the model id you want from the llm gate.

7 · Write a plan

A plan is one thing your agent knows how to do. You do not start from a blank file:

ekka plan template ask.json --gate llm --op infer --model anthropic/sonnet-4

That writes a complete plan file and prints the exact next commands. The file carries its own name (ask.v1, taken from the filename) in a plan block at the top, with the steps beside it, so nothing else is needed to create it. Use a model id your llm gate actually advertises. If you leave --model off a gate that offers more than one, the refusal lists the ones you can pick from.

8 · Create it, and watch your agent appear

The file is the whole plan, so create takes nothing but the file. (When you start editing plans, ekka plan validate ask.json runs every check create would while creating nothing: the same command CI can run.)

ekka plan create ask.json
✓ Plan created: [email protected]
  This plan runs as agent 6e0f42b9-…

That is Act 2 happening. The plan did not create an agent, it joined the Core Agent you already had; the long id above is that agent's internal id. Commands address an agent by its code, the first column of ekka agent list, which is core-979f755d in this walkthrough (yours will differ, and it never changes). Look at it now, and notice the declaration is no longer empty:

ekka agent list
ekka agent show core-979f755d

The plan needed llm.infer. Your agent had not declared it, so saving the plan widened your own agent's declaration and show now lists it with [email protected] beside it. That is allowed because you own this agent and have never published it.

It is also exactly why an agent you installed cannot do that. Its declaration is the list your organization read and agreed to, so a plan of the publisher's that needs more is refused instead of quietly growing the list behind you. Same rule, opposite outcome, and the difference is who owns the agent.

9 · Authorize it and run it

Declaring is the ask. A grant is the access, and it names which resource. It also names which gate instance serves it, which ekka gate list printed above as llm/<instance>:

ekka gate grant add --type llm --instance <instance> \
    --resource anthropic/sonnet-4 --capability llm.infer
ekka plan run [email protected] --input user_message="In one sentence, what is a governed run?"
✓ Plan completed (run 8f2c1b6e-…).

The model call happened from your Enclave. EKKA authorized it and recorded it, and the prompt and the answer stayed with you.


Act 4 · Now bring your own API

About 5 minutes.

Here is the part that decides whether EKKA is useful to you. One api gate turns any HTTPS API into something your agents can call and you can govern, so the API does not have to be one anybody integrated for you. The internal service only your company runs works the same way as a public one.

The example below uses a public weather API so it runs for everybody.

Your version of this

Read every apis/weather below as the system you actually care about: your CI server, your ERP, your helpdesk, your billing service, your internal reporting API. If it speaks HTTPS and takes a key, this act is unchanged.

Sign up for a key at weatherapi.com, or use a key you already have for an API of your own.

10 · Put the credential in the gate

export WEATHER_API_KEY=<your key>
printf '%s' "$WEATHER_API_KEY" | ekka gate credential deposit weather-key --gate api

The secret goes in on stdin, so it never lands in your shell history and never appears on a command line. From here on it is referenced by name.

The credential lives in the gate. Not in the agent, not in the plan, not in the model context. Your agent asks for apis/weather; the gate is what attaches the key. The agent cannot read it, print it, or leak it, because it never has it.

11 · Point an alias at the API

ekka gate alias create apis/weather --gate api --target '{
  "base_url": "https://api.weatherapi.com",
  "auth_template": { "kind": "api-key-query", "param": "key" },
  "credential_ref": "weather-key",
  "rules": [{ "method": "GET", "path_prefix": "/v1" }]
}'

That is the whole integration. Four facts:

Field What it is
base_url The origin, HTTPS only, no path. Calls can never leave it.
auth_template How the key is attached. bearer, api-key-header, api-key-query, basic, or aws-sigv4.
credential_ref The name you deposited in step 10. Never the key itself.
rules Optional allowlist of method plus path prefix. Leave it out and the whole origin is reachable.

The label must be two segments, apis/<name>, and the first segment has no hyphens. Aliases never rebind: to rotate a key, deposit a new ref and create a new alias.

12 · Write, create, authorize, run

ekka plan template weather.json --gate api --op read
ekka plan create weather.json

plan template prints the exact ekka gate grant add line for your gate, with the instance already filled in, and plan create prints it again for anything still missing. Run it, then run the plan:

ekka gate grant add --type api --instance <instance> --resource apis/weather --capability api.read
ekka plan run [email protected] \
    --input resource=apis/weather \
    --input key="/v1/current.json?q=London"

resource is which alias to call. key is the path and query on that alias. One plan file serves every path on that API, so you do not write a plan per endpoint.

Act 4 done

You just built an AI application against your own API, without writing a line of access-control code or a line of audit code.


Act 5 · See the governance

About 2 minutes.

Two commands. The first is a refusal you cause deliberately.

13 · Ask for something the agent never declared

Your agent declares llm.infer and api.read, because those are what its plans use. It has never asked to write to your API. Try to grant it that anyway:

ekka gate grant add --type api --instance <instance> --resource apis/weather --capability api.write
ekka gate grant: This agent does not declare 'api.write', so a grant for it
cannot be issued. If the agent should have it, widen its declaration first
(`ekka agent declare <agent-code> --add api.write`); the grant then names WHICH
resource it may touch.

Read what just happened. The platform said no by name, it named the rule it was enforcing, it named the remedy, and it did all of that before any HTTP request existed. Nothing was tried and then quietly rolled back. Nothing was tried at all.

That is what holds an agent: a declared list, an explicit widen, and a refusal that cites the rule. Not a prompt asking it to behave.

14 · Verify what actually happened

ekka receipts verify

It answers with how many records checked out, that nothing has been changed, added or removed since the first one, and how many carry a signature from this machine's Enclave.

Every step that ran is signed, and each signature covers the one before it, so the entries form a chain. Change any entry and every signature after it stops matching. verify recomputes the chain and checks the signatures against keys EKKA publishes openly, which is why it works offline and why someone who does not trust you can still check it.

To read one run rather than verify the whole chain:

ekka run list
ekka run show <run-id>
ekka receipts show <run-id>

What you actually built

Gates are how work flows: a model, an API, a database, a folder. That part is plumbing, and plumbing is not the product.

The product is the other four things. Your agent declares what it wants before it runs. Installing it consents to that exact list, and a change to that list has to come back and ask. Anything outside the list is refused by name, before any I/O, and the refusal is recorded like everything else. And what did happen comes back as a receipt anyone can verify without your login, our help, or your word for it.

That is what makes it rational to hand an AI agent a key to a real system.


What's next

Two things turn today's agent into something that works while you are not watching. Both are already in the binary you installed, and the financial analyst clone recipe walks both end to end.

  • Give it a folder you already own

    ekka enclave start <id> --data <folder> points your agent at data you already own (a source tree, a documents folder) and it refuses every operation that tries to leave it. Optional, and most Enclaves never need it. The files stay in the clear on your own disk, because you are still using them: EKKA authorizes and receipts every access, and never sees the path or the contents.

  • Give it a heartbeat

    ekka plan schedule runs a plan on a cron or a simple interval, for your organization only. Every scheduled run is an ordinary governed run: same grants, same refusals, same receipts. There is no quieter path for timers.

  • Stop writing the same steps twice

    ekka skill promote turns an operation you already wrote into a skill: a body of work published under a name, that any plan can call in one step. A published version is never rewritten, so a plan that names @1 keeps running what it ran the day you wrote it.