Install, try it on one repo, then run the admin web app locally. Every command in order, and what to do when one fails.
Private beta · free · takes about 10 minutes
One static binary, no runtime, no account. Distribution is private: there is no public repository, no package on a registry and no open download, so the routes below are the ones that exist today. The package-manager routes (Homebrew, Scoop, WinGet, npm) are not available and will not work — they are listed here only so you know not to try them.
| Route | What you do | Available |
|---|---|---|
| macOS, Linux | Run the install.sh we send you, with the build location set | yes, with access |
| Windows (PowerShell) | Run install.ps1 the same way; per-user, no elevation | yes, with access |
| Air-gapped | Take skeg-<os>-<arch> from the build we send, verify its checksum, put it on PATH | yes, with access |
| From source | make build in the repository (Go 1.22+, no third-party dependencies) | yes, if you have the repo |
Homebrew · Scoop · WinGet · npx · go install | Nothing — no package is published under any of these | no |
Request access with your team size, the agents you use and what you want working in week one. We reply within one business day and send a signed build for your platforms, its checksums, and the licence terms in writing.
There is deliberately no .msi or setup wizard. Skeg is one executable on your PATH; an installer package would add an uninstall entry, possibly ask for administrator rights, and give you nothing a copy of a file does not. The Windows script installs per-user into %LOCALAPPDATA%\Programs\skeg and needs no elevation.
Both installers verify integrity: they check the download against the signed SHA256SUMS that ships with the build and refuse to install anything they cannot match. Read install.sh or read install.ps1 before running either — they are short, and you should.
| Variable | Use |
|---|---|
SKEG_INSTALL_DIR | Install somewhere specific |
SKEG_VERSION | Pin a version, or take a release candidate |
SKEG_SHA256 | Pin one exact build by checksum |
SKEG_DOWNLOAD_BASE | Install from your own mirror or an air-gapped bundle |
$ skeg version skeg 1.0.0-rc2 (Apron, release candidate) $ skeg level 0 · not started next: skeg try
Bare skeg always prints where you are and the single next step. skeg glossary <term> explains any word it uses.
$ cd your-repo $ skeg try added 23 files (tracked) · baseline: 0 high · level 1 · TRY $ skeg undo # removes exactly what it added; your files untouched
The exact file count varies: Skeg keeps any file you already have, so a repository with its own .gitignore or PR template gets fewer. No gateway, no account, no login. You get the docs skeleton, agent rules (CLAUDE.md, AGENTS.md, .cursorrules from one source), a PR template, CI gates and a security scan of the working tree and git history. Endpoint hooks start in audit mode — they log, they do not block.
Worth trying next, in the same repo: skeg spec new "Your feature" --ticket AB-1, then skeg status, then skeg review --dry-run.
Adding a repo also writes PROJECT.md. Before it existed, the rules lived in files addressed to something other than a person: CLAUDE.md for agents, gates.yml and skeg-policy.json for CI and the hooks, and an empty docs/00-overview.md placeholder. Everything was written down and none of it was written to the developer, so the usual way someone met a guardrail was having a pull request stopped by it. That teaches a rule as an obstacle instead of as a reason.
The page covers what the project is, every gate that will stop a pull request, what the agent hooks block on this machine, where AI traffic goes — and, plainly, what is not watched. That last part is deliberate: the local CLI is not an access-control boundary, a developer will work that out eventually, and it is better they read it from us than discover it and conclude that nothing is enforced. The page says where the real boundaries are (branch protection, CI gates, required review, egress) so the conclusion they draw is the correct one.
$ skeg guardrails # regenerate after the config changes $ skeg guardrails --check # fails if the page no longer matches what is enforced
Every rule on it is read from the files that enforce it, so it cannot quietly disagree with them: move the size cap and the sentence moves. The --check form runs as a CI gate in the repo template, so a page that has drifted fails the build rather than misleading people. If your team would rather write the page by hand, delete the generated marker at the top and --check leaves it alone.
This is the local web app. It is part of the same binary — nothing extra to install, no Node, no Docker, no account.
$ skeg onboard --company "Your Co" # creates the workspace folder $ cd your-co-engineering $ skeg admin admin app on http://127.0.0.1:4200 · ctrl-c to stop
Open that address in your browser. It binds to the loopback interface, so it is reachable only from your own machine unless you deliberately change that.
| Flag | What it does |
|---|---|
--listen 127.0.0.1:4200 | Change the port, or bind elsewhere if you know what you are doing |
--workspace . | Point at a workspace folder other than the current one |
--workspace-repo <org>/<name> --create | Back the workspace with a private git repo: every change you make in the app is committed and pushed |
By default a local single-owner run has full access. To split duties, set roles before starting:
$ SKEG_ADMIN_ROLES="tok-a:admin,tok-s:security,tok-p:product-lead" skeg admin
Behind an SSO proxy (oauth2-proxy, Pomerium, IAP) use header-based identity instead — set SKEG_ADMIN_SSO_HEADER and map your groups to roles. Admin ⊇ security ⊇ product-lead ⊇ viewer; every mutating action is written to a hash-chained audit log you can verify.
--workspace-repo set, everything you click becomes a commit in your own private repo. Configuration stays reviewable, diffable and revertible instead of living in someone else's database.Only needed when you want the AI gateway, real logins, budgets and dashboards. Everything above works without it.
$ cp .env.example .env # fill: provider key, master key, one login provider $ docker compose up -d # gate, authd, Postgres, Redis, logs, dashboards $ curl -s localhost:4000/skeg/health
Then each developer runs skeg login --gateway https://<your-gate>, optionally skeg hooks install for endpoint governance and skeg agent install for continuous coverage. Kubernetes: helm install skeg deploy/helm/skeg gives multiple replicas, autoscaling, network policies and TLS. Fully offline: add docker-compose.local-model.yml and run your own model.
Which models? Set two lines in skeg/models.yaml — any OpenAI- or Anthropic-style endpoint works, hosted or self-hosted. Check with skeg models.
Nothing about this is specific to any one project, and none of it needs an admin. The three commands are the same whether the project is a payments service, a marketing site or an internal tool, and the first two need no token, no login and no gateway — they only write files, so adding a project arrives as an ordinary pull request that someone reviews.
$ skeg project new checkout --type product # product | client | internal | experiment $ skeg init --project checkout # in the repo that holds the code $ skeg repo connect acme/checkout --project checkout # gates, branch protection, CI variables
The first command writes product/checkout/: a README naming who owns it and which repositories it covers, a roadmap, a spec template, and policy.yaml — the project's own overlay for budgets, data class, model allow-list and enforcement. The overlay may only tighten the company baseline, never loosen it.
Fill the README in. skeg doctor names any field still blank, and it is not pedantry: Repos is what says which code that policy governs, so an empty one means the budgets and enforcement you just set apply to nothing anyone can name.
Only the third command needs a GitHub token, because it is the one that changes a repository: it pushes the gates workflow, sets branch protection and writes the CI variables. It checks first that the Skeg actions ref it is about to write actually resolves, and refuses if it does not — a repository whose gates cannot run is not governed, and reporting it as connected would be a lie you only discover on the first pull request.
Every fresh agent session starts from nothing. So you re-explain the codebase: what this service is, what you are actually building, the thing you decided last quarter and must not undo, the bug this file already had once. You type some of it, forget the rest, and the agent confidently does the forgotten part wrong.
Your repository already holds all of it — in the spec, in docs/01-architecture.md, docs/03-decisions.md and docs/06-troubleshooting.md. skeg context assembles the parts that apply to the files you are touching and prints them.
$ skeg context ## What this change must do Spec: product/invoices/specs/pdf-invoices.md (status approved) - [ ] a merchant can download an invoice as a PDF **Explicitly NOT part of this change — do not build these:** emailing the PDF; bulk export ## Decisions that already apply here - **Renders must be deterministic** — render.ts must not read the clock. - **Never send email from a test or a script** — only mailer.ts sends. ## This code has broken before - Old invoices re-render differently · render.ts · a Date.now() crept in
Four things it does deliberately:
It filters. Only the decisions and recorded failures touching the files in your diff. An unfiltered brief is read by nobody, which makes it the same as no brief.
It keeps standing prohibitions regardless. A rule like “no Redis in this service” names no file, so file-matching drops precisely the rules agents break. Those are always included.
It phrases out-of-scope as an instruction. Not a heading called “out of scope”, which a model reads as context, but do not build these. Agents build the adjacent feature nobody asked for unless told not to, in those words.
It names what is missing. If nobody has written down what the project is for, or the spec's acceptance criteria are blank, the brief says so under “treat these as unknown” rather than quietly omitting it. A brief that sounds complete when it is not is worse than none, because the agent proceeds confidently either way.
It runs offline, needs no gateway and no key, and goes wherever you want it:
$ skeg context | pbcopy # into the chat $ skeg context --for src/pay.ts # a file you have not touched yet $ skeg context --quiet > brief.md # into a prompt, a PR, a ticket
Your agent can also fetch it without you — that is the skeg_context tool below.
Most AI coding now happens inside an agent, so Skeg speaks MCP. Instead of hitting a gate at pull-request time, the agent can check its own work while it writes.
$ skeg mcp install # prints the config for Claude Code, Cursor, Windsurf
Six tools, all read-only: skeg_spec_get (what was actually asked for) · skeg_review (in scope, out of scope, not evidenced — the same verdict CI will give) · skeg_gate_preflight · skeg_why · skeg_scan · skeg_context.
Advisory only, and this is a design rule rather than a setting. There is no method to approve a spec, weaken a hook, change enforcement or touch an entitlement — those methods do not exist in the server. If the agent being governed could call them, a prompt injection in any repository file could switch off its own governor. Hooks and the gate work precisely because the agent cannot reach them. A release-blocking test fails the build if a mutating tool is ever added.
Output is framed as data, not instructions. Every response is wrapped in labelled JSON with an explicit note that the content is untrusted repository text, so a spec containing “ignore previous instructions” arrives as a string in a result field rather than as prose your model reads as direction. A release-blocking test plants exactly that injection in a spec and asserts it comes back framed.
Being straight about the limit: framing is a mitigation, not a cure. No wrapper can guarantee a model ignores text inside it. What makes this safe is the first rule — even a model that follows an injection cannot disable a hook, approve a spec or change policy through this server, because those methods do not exist. The framing reduces the chance of a bad suggestion; the missing methods remove the chance of a bad action.
Every call is written to ~/.skeg/audit-mcp.jsonl, so “what did the agent ask Skeg, and what did Skeg say?” is answerable afterwards — including the calls that were refused.
Developers are not obliged to use the command line. skeg ui opens a local page for the repository you are in: the same commands as buttons — where am I, check my branch, find secrets, am I hardened, specs, health, AI tools on this machine — plus fields for creating a spec or pasting a gate failure to have it explained.
$ skeg ui Skeg UI: http://127.0.0.1:4210 (this repository: /home/you/your-repo) Loopback only, no authentication, nothing leaves this machine. Ctrl-C to stop.
Three deliberate constraints. It runs Skeg's own commands and shows their real output, so there is no second implementation and the window and your terminal can never disagree. Actions are allow-listed, so it cannot become a remote shell on a developer's machine — which is exactly what Skeg's own hooks exist to prevent. And it refuses to bind to anything but loopback, because it is unauthenticated by design.
Every result names the command that produced it, so the window is a way into the terminal rather than a substitute that hides what happened.
Whoever owns the product should not need a terminal, a server or a login to see the state of it. skeg brief writes one page from the repository: what shipped, which specs are waiting on them, the security baseline, how stale the documentation is, and one decision to make this week — because a brief asking for five gets none.
$ skeg brief # read it here $ skeg brief --out brief.md # paste into Slack $ skeg brief --html brief.html # a page they double-click $ skeg brief --days 30 # a month instead of a week
The HTML page is entirely self-contained: no server, no JavaScript, no external requests, and it prints cleanly — so it can be emailed, opened offline, or taken into a meeting on paper. Run it from a scheduled job on Mondays and the ritual maintains itself.
It reports only what it can read from the repository and says so where it cannot: cost, cycle time and model usage need the gateway, and it points at the dashboards rather than inventing figures.
Having Skeg installed is not the same as being hardened. skeg harden audits the difference and prints what it looked at, so a disagreement is about facts rather than claims.
$ skeg harden [ ok ] R2 repository CI gates committed [ FAIL ] R1 endpoint Hook enforcement — enforcement=audit: actions are logged only [ ?? ] X2 network Provider egress restricted to the gate — verify by hand 14 checks · 3 failing · 6 need manual verification
It checks the repository (gates committed, CODEOWNERS on .github/ so the gates cannot be disabled in the same PR, no open high findings, no secrets in committed config), the endpoint (hook enforcement mode), identity (a Skeg-issued key within its 24-hour expiry, and no provider keys sitting in your environment where a tool could bypass the gateway), and the gateway (TLS, readiness).
Five controls report UNKNOWN and never PASS, because they live on hosts Skeg cannot see and they are the ones that actually stop a determined bypass: branch protection including administrators, provider egress restricted to the gate at the firewall, SCIM deprovisioning, audit shipped to append-only storage, and organisation-level required workflows. A hardening report that guessed would be worse than none, because it gets pasted into a security questionnaire.
--json for CI, --strict to fail the build on unverified controls too.
Plain SemVer, and the promise matters more than the number: a patch is fixes only and always safe to take; a minor adds capability and will not change an existing command, config or gate verdict; a major breaks something and is announced 90 days ahead with a migration path and a deprecation warning from the CLI first.
Minor releases carry a codename, alphabetically, from the parts of a hull: 1.0 Apron, 1.1 Ballast, 1.2 Chine, 1.3 Deadwood, 1.4 Futtock, 1.5 Garboard. Names are for humans and never appear in a tag or a filename. skeg version prints both.
| Channel | Get it with | For |
|---|---|---|
| stable | the installer, by default | everyone |
| release candidate | SKEG_VERSION=v1.2.0-rc1 | design partners and the impatient |
| dev | main + make build | people building Skeg |
Each minor is supported until two further minors ship. Security fixes land on the current stable and the one before it.
No CLA, and you keep your copyright. Sign off your commits with git commit -s. Setup is two minutes: clone, make build, bash tests/regression.sh.
Know which part you are editing, because the licence differs by directory: cli/, templates/, dashboards/ and deploy/ are Apache-2.0; gate/, authd/ and collector/ are BSL 1.1 (readable, free to self-host internally, Apache-2.0 after four years); handbook/ and this site's writing are CC BY-NC-ND. Contributions are accepted under the licence of the directory they land in. There is one Skeg and one repository: the paid tier is a licence over the same build, not a separate product, so nothing is hidden from the people who contribute to it.
One additional grant, stated plainly because you should know what you agree to. Signing off also grants Skeg a non-exclusive, perpetual right to offer your contribution under other terms, including commercial ones. You keep your copyright and every right to your own work. This avoids the project becoming unable to change its own licensing because one contribution cannot be relicensed and its author is unreachable — a common way open-core projects die, and far narrower than a copyright-assignment CLA. If you would rather not grant it, say so in the pull request and we will either write the change ourselves or decline honestly.
Easiest useful contributions: a stack pack (templates/repo/stacks/<name>/ — lint, test, build, CI job, agent rules; no Go at all) · a redaction pattern the gate misses, with its canary case · a skeg why explanation for a confusing gate failure · a glossary entry (CI fails if a term is undefined) · a hook rule for a destructive command we do not catch · an IDE or agent integration · making an error message less irritating, which is the highest-leverage work in the repo.
Pushed back, and why: a third-party Go dependency in the CLI, gate or authd (standard library only — it is a supply-chain promise) · a hard-coded model name (a CI guard fails the build) · a behaviour change with no test · telemetry that collects more · anything that needs customer content to leave their network · a 900-line PR, held to the same size gate as everyone.
Use skeg spec new then skeg pr: the same loop the product asks of your team. If an agent wrote most of it, say so in the PR — that is normal here.
From the terminal where it happened. It prints exactly what would be sent first — version, platform, and whether a repo, template and hooks are present. Never your code, paths, branches or prompts.
$ skeg feedback bug "pr guessed the wrong ticket" $ skeg feedback suggestion "let me skip the size cap on docs-only changes"
Prefer writing? Use the form or email feedback@skeg.dev.
| Symptom | Fix |
|---|---|
skeg: command not found | The install directory is not on your PATH. The installer prints the exact export line to add. |
Installer says it cannot fetch SHA256SUMS | The release is not published yet, or you are offline. Point SKEG_DOWNLOAD_BASE at a location that serves the binary, or pin SKEG_SHA256. |
| Admin app: port already in use | skeg admin --listen 127.0.0.1:4300 |
| Admin app: blank or missing data | Run it from inside the workspace folder created by skeg onboard, or pass --workspace <path>. |
| Repos screen: Connect fails | A repository token is needed. Add it on the Settings screen, or export GITHUB_TOKEN before starting. It needs contents, administration, actions variables and issues. |
| 403 from the admin API | Roles are configured and your token or SSO group does not have the required role. Policies need security; company and repos need admin. |
| A gate failed and the message is unclear | skeg why "<the message>" explains it and gives the fix. |
| Anything else | skeg doctor checks identity, gateway, template, rules, secrets, hooks and docs freshness in one pass. |