Browse the docs

DocsStart here

Install Ekwo OS on your own Supabase project

Once installed, the company is run from the web application, Ekwo Cloud — which opens your own instance as well as a hosted one — or through the command line, the MCP server, the REST API Supabase generates from the schema, or @ekwo-ai/core.

From a free Supabase account to a first invoice

  1. Create a project at supabase.com. The free plan is enough to start. Ekwo does not create it, does not pay for it and has no access to it: it is yours from the first row.

  2. Copy two things from the dashboard:

    • Connect → Session pooler: the connection string. It contains your database password. Take the session pooler line rather than the direct one: the direct host answers on IPv6 only, which many networks cannot reach.
    • Project Settings → API Keys: the secret key (sb_secret_…, or the legacy service_role key on an older project) and the Project URL. They are used once, to create the first administrator in your own Supabase Auth, and are never written to disk.
  3. Run the installer.

    npx -y ekwo-os@latest init
    

    It asks for the connection string, the country, the chart of accounts and the language where the pack offers a choice, your organisation, the currency, the first company, the address of the first administrator and — optionally — your main bank account, written the way your country's banks write it. A few seconds on a free project. Nothing is preselected on the three questions whose wrong answer is expensive: the country, the chart and the language.

  4. Sign in as that administrator and start booking — in the web application, Ekwo Cloud, which opens your own instance; through an AI agent and the MCP server; from this command line; or through the REST API Supabase generates.

  5. Do the four things below while the dashboard is still open. The installer prints them at the end of a successful run.

Everything above in one non-interactive line:

npx -y ekwo-os@latest init \
  --db-url "postgresql://postgres.YOURREF:PASSWORD@aws-1-REGION.pooler.supabase.com:5432/postgres" \
  --supabase-url "https://YOURREF.supabase.co" \
  --service-role-key "$SUPABASE_SERVICE_ROLE_KEY" \
  --country <cc> \
  --org "My Organisation" \
  --company "My Company" \
  --admin-email "you@example.com" \
  --admin-password "a-long-password" \
  --fiscal-year 2026 \
  --yes

With --yes nobody is asked anything, so ekwo init refuses rather than choosing for you: no country without --country, and --chart, --language or --fiscal-year-start wherever the country's pack offers more than one answer. Each refusal lists the values the pack accepts. ekwo pack describe <cc> (in a clone) or the country's page on ekwo.ai/countries says which a country needs.

Several countries in one installation: init --no-company

An installation is not in a country; its companies are. ekwo init loads every pack of the release whatever --country says, so one installation keeps the books of companies in as many countries as it holds packs. When there is no "first company" to name — a group, a firm, a holding with subsidiaries abroad — install without one, then create each company in its own country:

npx -y ekwo-os@latest init --no-company \
  --db-url "$EKWO_DB_URL" --supabase-url "https://YOURREF.supabase.co" \
  --service-role-key "$SUPABASE_SERVICE_ROLE_KEY" \
  --org "My Group" --admin-email "you@example.com" --yes

ekwo company new "My Company One" --country <cc> --yes
ekwo company new "My Company Two" --country <other cc> --yes
ekwo company list

--no-company refuses every flag that only describes a company — --country, --chart, --language, --currency and the rest — since there is no company for it to describe. ekwo company new is the same create_company() the MCP tool calls: it runs as an administrator of the installation (--as-user, or the only one), asks the same questions as init and refuses the same way off a terminal.

Before you go live: four things on your project

An installation leaves four things undone on purpose: they are yours to decide, on a project Ekwo has no access to. ekwo init prints this list at the end of a successful run.

1. Turn off self sign-up on your project. Supabase dashboard → Authentication → Sign In / Providers → "Allow new users to sign up", switched off. An Ekwo installation is closed: the people who keep the books are invited. A stranger who signs up sees nothing, but there is no reason to let them in.

2. Keep two administrators. An instance administrator invites everybody else. With one, a lost password or a closed mailbox is a set of books nobody can let anyone into. Create a second account and add it with claim_instance_admin(), or invite it from the application.

3. Keep the service_role key off every machine that does not need it. A request carrying it bypasses row level security and reads every company in the instance. This CLI uses it once, to create the first account, and writes it nowhere. --admin-user-id installs against an account that already exists and needs no key at all. A script that needs to work on its own gets an API key, scoped to one company.

4. Read DISCLAIMER.md before you file anything. DISCLAIMER.md, at the root of the repository. A country pack is a reading of a country's rules at the date of its version. ekwo init prints the review status of the pack it installs for the same reason. The books are yours, in every country where you file.

What init does, step by step

Step What happens
1 Applies supabase/migrations/*.sql in order, recorded in the Supabase CLI's own history table — so supabase db push and ekwo migrate stay interchangeable
2 Applies every reference seed: currencies, territories, the generic financial statements, and every country pack of the release
3 Creates the first administrator through the Supabase Auth admin API — a database connection cannot be a signed-in user, which is the only reason the secret key is asked for
4 Records the instance, takes the administrator seat, creates the company with you as owner, copies its country pack, opens the first financial year, and adds the bank account when one was given
5 Writes ekwo.json: the project URL and the schema version, nothing else
6 Asks whether to register with Ekwo; the default answer is no

Every step checks before it acts. Running ekwo init twice on the same project reports what was already there and creates nothing a second time.

Rendered from packages/cli/README.md, in the repository, when the site was built. Read or change it on GitHub