# Cyrus ships MIT in its package manifest and Apache 2.0 in its README

> An issue-driven coding agent that claims to be free to self-host, where self-hosted carries two different meanings across the pricing tiers, the documented install command still points at the repository's former GitHub path, and the linter is configured to rewrite code on every commit.

**cyrusagents/cyrus** — The Claude Code background agent for Linear, Slack, Github, GitLab etc. you deploy anywhere. Supports Codex, Cursor, Gemini, and Opencode harnesses too.

- Repository: https://github.com/cyrusagents/cyrus
- Website: https://atcyrus.com
- Stars: 843 · Forks: 174
- Language: TypeScript
- License: Apache-2.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/cyrusagents-cyrus

## The install command names a different repository path

The command the page gives for community installation is:

```bash
npx skills add ceedaragents/cyrus -g
```

The build badge at the top of the same file points at github.com/ceedaragents/cyrus/actions. Neither path is the one you cloned: the repository lives at cyrusagents/cyrus, and the manifest's own repository field agrees with that, while its author field is recorded as Ceedar. So the setup instructions, the badge and the manifest were written against two different organisation names, and a reader who follows the documented command is pulling a skill from somewhere other than the tree they are reading. Once installed, the flow is a single slash command, /cyrus-setup, run inside any supported agent, with a manual path offered as an alternative through docs/SELF_HOSTING.md.

## The licence is stated twice, differently

The closing section of the page says the project is licensed under the Apache 2.0 licence and points at the LICENSE file, and the repository's own licence metadata agrees. The root package manifest says something else. Its license field reads MIT, inside a manifest that is otherwise careful, with an exact pin on its only runtime dependency, the Linear SDK at 60.0.0. That matters more than a documentation nit, because the manifest is the file package managers read when they install anything from this project, so a consumer checking the published artefact sees MIT while a reader of the page sees Apache 2.0. Nothing in the page reconciles the two, and the page does not describe the manifest as covering only the monorepo shell, which is the usual reason a root package carries a different licence from the source it orchestrates.

## Self-hosted means two different things in one page

Three deployment shapes are offered and the middle one is not what its name suggests. The community path is described as a zero cost option where you host everything yourself, including your own Linear OAuth app, your own GitHub App and your own Slack App, onboarded by an AI guided setup skill that installs dependencies, configures auth, creates the integration apps and connects repositories. The paid self-hosted tier is described in narrower terms: it is called self-hosted because it uses a machine you control as the agent runtime, while the networking layer and the integrations are provided by the Cyrus cloud provider, and installation is a global npm install of cyrus-ai followed by cyrus auth with a token issued during onboarding. The third shape installs nothing at all. The token side is BYOK throughout, so the model comes from your own subscription rather than the vendor.

## The agent is a long-lived process that drives your git CLI

Cyrus watches issues assigned to it, creates an isolated Git worktree per issue, runs a session in it and streams activity back to Linear or GitHub, including dropdown selects and approvals. That loop only works while something stays up, and the page gives three ways to keep it running: a tmux session created with tmux new -s cyrus and then detached with Ctrl+B followed by D, pm2 started as pm2 start cyrus --name cyrus, or a systemd unit documented separately. Reaching the repository is by shelling out, since creating a pull request or merge request requires your Git configuration and your hosting CLI, which is why there are separate guides for the GitHub and GitLab paths. A Cloudflare Tunnel guide is also included for exposing a local instance, which turns a machine on your desk into something with an inbound URL.

## Sixteen transitive packages are forced upward by hand

The manifest is a pnpm workspace declaring pnpm 10.33.1 as its package manager, and its pnpm block does two unusual things. onlyBuiltDependencies names one package, sqlite3, as allowed to run install scripts, which is the narrower half of a pnpm 10 policy. The overrides list then pins sixteen transitive dependencies to floors, from uuid at 11.1.1 and js-yaml at 5.2.2 through simple-git, undici, hono, ajv, picomatch and grpc-js, each written as a lower bound rather than an exact version. Read together, that is a supply chain posture expressed in configuration: a specific set of packages is never allowed to resolve below a chosen version, and everything else floats. One more setting deserves a look before committing, since lint-staged runs biome check --write --unsafe across JavaScript, TypeScript and JSON on every commit, and the unsafe flag applies fixes that can change behaviour rather than only formatting.

## Two lockfiles, and the type checker is a dated nightly

The workspace carries both pnpm-lock.yaml and a bun.lock at the top level while naming pnpm as its package manager, so two runtimes have a record of the dependency graph and only one is the declared one. The build script is pnpm recursive with a filter that excludes the Electron package by name, which is a quiet admission that the workspace contains a desktop app that is not part of the library build. Tooling is otherwise current and slightly experimental: Biome 2 for both lint and format, husky wiring the commit hook, and a type checker pinned to an exact dated development build of the native TypeScript preview rather than to a release. The filter also means a broken app under apps/ will not stop a library build, and a passing library build says nothing about the app.

## Zulip appears in the documentation and not in the feature list

The sentence that says what Cyrus is names four integrations, Linear, GitHub, GitLab and Slack, and the repository description names the same set. The documentation list adds a fifth: docs/ZULIP.md, for answering at-mentions in Zulip topics and direct messages. So the integration surface described by the docs is wider than the one described by the headline, and nothing on the page says whether Zulip is complete, partial or experimental. The same asymmetry shows in the credits, which name only the Linear API and Anthropic Claude Code, while the harness list at the top names five agents, Claude Code, Codex, Cursor, Gemini and Opencode. The rest of the documentation index is setup oriented: a configuration reference for config.json, a Git and GitHub setup guide, a Git and GitLab setup guide, setup scripts for repository and global initialisation, and the community self-hosting manual.

## Four tool directories, four code roots, two changelogs

The top level carries the footprint of a project that installs itself into other tools. Four configuration directories are committed, .claude/, .codex/, .opencode/ and .vscode/, and two instruction files sit beside them, CLAUDE.md and AGENTS.md, as does CONTRIBUTING.md. There are two changelogs, a public CHANGELOG.md and a CHANGELOG.internal.md, and no explanation of the split. Code lives under four roots rather than one, apps/, packages/, code/ and spec/, which is a monorepo with a second monorepo inside it. The rest is operational: a cyrus-setup.sh shell script at the root, a skills/ directory, docs/, scripts/, biome.json for the formatter configuration, and a single tsconfig.base.json that the four roots extend. The manifest describes itself as a monorepo for a Linear Claude agent integration and is marked private, so none of this is published to a registry under that name.

## Conclusion

Before running Cyrus, settle three things the page leaves open. The licence is stated two different ways, and the manifest is the one npm consumers see. The community path is the one that is genuinely self contained, since it is you who create the OAuth app, the GitHub App and the Slack App, while the paid tier keeps the vendor's network edge. And the daemon needs a persistent process, repository write access through your authenticated CLI, and optionally a public tunnel, so the blast radius is the machine it runs on.

## FAQ

### What does Cyrus do with an issue assigned to it?

It creates an isolated Git worktree for that issue, runs a Claude Code, Codex, Cursor, Gemini or Opencode session in it to process the work, and streams detailed activity back to Linear or GitHub, including dropdown selects and approvals. Progress is reported as the harness runs rather than as a summary at the end.

### Is Cyrus free to self-host?

The community path is described as a zero cost option where you host everything, including your own Linear OAuth app, GitHub App and Slack App, set up either by an AI guided skill or the manual guide. The paid self-hosted tier still uses the vendor's networking layer and integrations, with the dashboard at app.atcyrus.com providing configuration.

### What licence is Cyrus under?

The page gives two answers. The README states the Apache 2.0 licence and the repository metadata agrees, while the root package manifest records MIT, and that manifest is the file a package manager reads on install.

### Does Cyrus need a model API key?

No. The page describes Cyrus as a BYOK platform for tokens, so you bring your own keys or subscriptions, and the model side is whichever harness you run, naming Claude Code, Codex, Cursor, Gemini and Opencode as supported.

### How does Cyrus create pull requests?

By shelling out to your Git configuration and your hosting CLI, which is why there are separate setup guides for GitHub and GitLab. The daemon itself has to stay running, under tmux, pm2 or a systemd unit, and a Cloudflare Tunnel guide is provided for exposing a local instance.

## Sources

- [cyrusagents/cyrus on GitHub](https://github.com/cyrusagents/cyrus)
- [License: Apache-2.0](https://github.com/cyrusagents/cyrus/blob/main/LICENSE)
- [Project website](https://atcyrus.com)
- [README](https://github.com/cyrusagents/cyrus/blob/main/README.md)
- [Releases](https://github.com/cyrusagents/cyrus/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/cyrusagents-cyrus
