Sno Station
Sno Station is your agents' workstation: open-source software that turns the AI agents you already run into one squad on your own machine. Two heads are better than one, and they get better with every
Linear workspace for Claude Code — search, bulk edit, agents, and a config-driven curator. The repo IS a Claude Code plugin marketplace.
PluginsTypeScript · PythonGitHub @Elnora-AISelf-installOwner unconfirmed
Paste into Claude or ChatGPT for installation instructions suited to your environment.
Have you tried it? One tap is enough. No sign-in needed.
Loading the full README. The saved excerpt is shown below.
The full Linear API as a CLI, a Claude Code plugin, and a signal-driven hygiene curator — purpose-built for AI coding agents to create, edit, review, and curate Linear issues safely at scale.
The CLI and the Claude Code plugin are two separate installs. The plugin's agents, skills, and slash commands all shell out to the elnora-linear binary — so you must install the CLI first, even if your only goal is to use the plugin. /plugin install does not install the CLI.
Step 1 — Install the CLI (required for everyone)Read the full README ↗The full Linear API as a CLI, a Claude Code plugin, and a signal-driven hygiene curator — purpose-built for AI coding agents to create, edit, review, and curate Linear issues safely at scale.
The CLI and the Claude Code plugin are two separate installs. The plugin's agents, skills, and slash commands all shell out to the
elnora-linearbinary — so you must install the CLI first, even if your only goal is to use the plugin./plugin installdoes not install the CLI.
npm install -g @elnora-ai/linear
elnora-linear issues list # prompts for your Linear API key on first run
Get a key at linear.app/settings/api. It's saved to ~/.config/elnora-linear/.env (mode 0600).
Auto-sync on install. If LINEAR_API_KEY is already in your environment (or saved at ~/.config/elnora-linear/.env) when you run npm install -g, the postinstall hook populates teams / projects / users / workflows from your Linear workspace. Otherwise run elnora-linear sync all later.
Escape hatches for the auto-sync (any one disables it): ELNORA_LINEAR_SKIP_POSTINSTALL=1, CI=true (auto-detected), or non-global installs.
Only after Step 1 succeeds. The plugin adds slash commands and dispatched subagents on top of the CLI. Run these as two separate slash commands (paste the first, hit enter, wait for it to finish, then paste the second):
/plugin marketplace add Elnora-AI/elnora-linear
/plugin install linear-workspace@elnora-linear
Verify both are wired up:
elnora-linear --version # CLI on PATH
Then /plugin inside Claude Code should list linear-workspace as enabled. If elnora-linear --version fails, go back to Step 1 — the plugin's agents will not work without the binary on PATH.
Install the CLI (Step 1 above), then drop AGENTS.md at your project root. These agents read it natively for the intent → CLI dispatch table. No plugin install needed — the plugin is Claude-Code-only.
Installing via an AI agent? Point it at
INSTALL_FOR_AGENTS.md— a gated, step-by-step runbook to verify the install, collect the key, sync references, and smoke-test.
Three surfaces, two installs:
elnora-linear CLI (npm package — Step 1 above) — complete coverage of the Linear GraphQL API. Scriptable, JSON-pipeable, structured errors that agents can self-correct from. Also ships elnora-linear curator-run, the config-driven automation that polls GitHub, Slack, and custom shell signals, asks an LLM what to do, auto-applies safe state changes (capped, debounced, audit-logged), and queues the rest for human review.linear-workspace Claude Code plugin (separate /plugin install — Step 2 above) — slash commands, five specialized agents, and a router skill that picks the right one from intent. Every agent delegates to the CLI from Step 1.Read — search, my-issues, get one issue / project / cycle / milestone / initiative / document, team workflows, label catalogs, members, saved views, project + initiative status updates, audit logs, notifications, agent activity, rate-limit headroom, context --team for one-call cold-start.
Write — create one issue or batches up to 50 (server-side label-policy + require-a-project validation), update every field, manage comments / relations / projects / initiatives / milestones / cycles / documents / status updates / labels / customers / customer needs / webhooks / agent sessions. Attach URLs or upload local files (path-validated, symlink-resolved).
Bulk + cleanup — bulk (state/comment changes across N issues, dry-run by default), cleanup (six-check audit), batch-create / batch-update (50-issue caps), bulk-ops (heterogeneous GraphQL aliasing — ~10 HTTP requests per 100 mixed operations), sync all, sync verify.
Compliance — templates/ ships 23 Linear issue templates (SOC 2, change mgmt, RCA, vulnerability, access provisioning, vendor risk, AI capability). elnora-linear templates list / templates sync push them to Linear.
Pipe — --output json on every read; --output csv and --output table where it makes sense.
Run elnora-linear --help for every verb.
| Command | Does |
|---|---|
/linear-search | Natural-language search across all issues |
/linear-my-issues | Your assigned issues, grouped by state |
/linear-bulk | Apply the same state change or comment to many issues — dry-run by default |
/linear-cleanup | Six-check audit with per-category confirmation |
/linear-sync | Refresh teams/projects/users/workflows from the Linear API |
/linear-curator-run | Run the curator manually |
| Agent | For |
|---|---|
linear-issue-creator | One issue from a description |
linear-url-to-issues | N issues extracted from an article, design, blog, or doc URL |
linear-issue-updater | Any modification: state, team, assignee, labels, comment, relations, close |
linear-issue-reviewer | Validates an issue's Done Criteria against its linked PR diff and posts a verdict comment |
linear-state-curator | Daily hygiene — runs the curator headlessly |
A router skill (linear-workspace) dispatches to the right agent or command from intent. Other agents (Codex, Cursor, and others) get the same dispatch mapping via AGENTS.md.
elnora-linear curator-run polls configured signal sources, builds an LLM snapshot of your open issues, and dispatches per tier:
{issue, from, to} debounced 14 days.~/.config/elnora-linear/state/curator-state.json for human review. Outbound Slack confirmation (DM-back + threaded replies) is in the spec but not yet shipped.| Signal source | Reads |
|---|---|
github_commits | Commit messages over a lookback window |
github_pr | Open / closed / merged PR events |
slack_messages | Watched channel history (Slack app setup: see INSTALL_FOR_AGENTS.md) |
external_command | Arbitrary CLI command output — off unless LINEAR_ALLOW_EXTERNAL_COMMAND=1 |
(mcp_tool is reserved in the schema for a future release.)
Every applied action is appended to ~/.config/elnora-linear/state/curator-report.jsonl. Without an LLM key (or with --collect-only), the curator runs in diagnostic mode. Any LLM key works — see Requirements. Recurring schedule: see docs/scheduling.md.
--permanent + --yes.--yes.issues create returns { missing, availableForPrefix, suggestedRetry } on label-policy violations and { availableProjects, suggestedRetry } on the require-a-project rule.issues create, issues batch-create, and issues bulk-ops (create) require --project whenever the target team has projects to choose from. Opt out per-team via label-policy.json (requiresProject: false) or per-call with --skip-project-check.issues create/issues update take --description-file, comments create/comments update take --body-file (- reads stdin), so fenced code blocks and quotes never pass through the shell. The inline and file options are mutually exclusive, and an unreadable, empty, or non-UTF-8 file is an error rather than a silent bad write — no encoding guessing, so a file written with the wrong encoding is caught before anything is sent.{issue, from, to} debounced 14 days; every applied action audit-logged.LINEAR_UPLOAD_ROOT with symlink resolution.LINEAR_API_KEY → ~/.config/elnora-linear/.env (mode 0600) → interactive prompt. Masked in errors, omitted from JSON output, redacted in logs.Full details in SAFETY.md.
| Always | |
|---|---|
| Node.js | >=20 |
| Linear account | Personal API key from linear.app/settings/api |
| Curator (opt-in per signal source) | |
|---|---|
| An LLM key | Any one of OPENROUTER_API_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY (or GOOGLE_GENERATIVE_AI_API_KEY), GROQ_API_KEY, DEEPSEEK_API_KEY, XAI_API_KEY or MISTRAL_API_KEY. The curator picks the provider from the key it finds (OpenRouter first when several are set; LLM_PROVIDER chooses; LINEAR_CURATOR_MODEL overrides the model). Any other OpenAI-compatible endpoint (Azure OpenAI, Together, Fireworks, LiteLLM, a self-hosted vLLM or Ollama) works with LLM_BASE_URL + LLM_API_KEY + LINEAR_CURATOR_MODEL. Without a key the curator runs in --collect-only diagnostic mode |
OPENROUTER_API_KEY | TypeSafe Jev check before a HIGH action auto-applies — without it every HIGH action is asked in Slack as MEDIUM instead |
gh CLI, authenticated | github_pr signal source |
git + local clone | github_commits signal source (repos.json entries need local_path) |
SLACK_TOKEN | slack_messages signal source (read-only — outbound posting not shipped yet) |
LINEAR_ALLOW_EXTERNAL_COMMAND=1 | external_command signal source (off by default) |
npm dependencies (bundled into dist/cli.js, nothing to install): @linear/sdk, @anthropic-ai/sdk, commander, ajv + ajv-formats.
Workspace config lives in ~/.config/elnora-linear/ (override with LINEAR_REFERENCES_DIR). The npm package ships placeholders only — populated *.json files are gitignored and excluded from the npm tarball.
.env # LINEAR_API_KEY (mode 0600)
teams.json # ← elnora-linear sync teams (auto)
projects.json # ← elnora-linear sync projects (auto)
users.json # ← elnora-linear sync users (auto)
workflows.json # ← elnora-linear sync workflows (auto)
label-policy.json # required labels per team (manual)
slack.json # channels for slack_messages (manual)
repos.json # GitHub repos the curator watches (manual)
signal-sources.json # curator inputs (manual)
Each file has a JSON Schema in schemas/ and a populated example at references/<name>.example.json. The loader validates every read. To finish curator setup, ask your agent: "set up my curator config" — it walks each manual file using the examples as templates. Run elnora-linear sync verify to see what's populated.
git clone https://github.com/Elnora-AI/elnora-linear.git
cd elnora-linear
pnpm install
pnpm typecheck && pnpm lint && pnpm test && pnpm build
Linting: Biome. Tests: Vitest. Releases: release-please.
Issues and PRs welcome — see .github/CONTRIBUTING.md. Security: .github/SECURITY.md or [email protected]. Licensed under Apache-2.0.
Open-source agent tooling from Elnora AI — free, universal, config-driven tools that wire Claude Code (or any AI coding agent) into the systems you run your company on. Each works 100% standalone; install several and they chain into end-to-end workflows. Take them all and you have the same system Elnora AI runs on internally.
The Elnora platform itself — the AI agent for lab work — is open too: elnora-cli (the Elnora CLI), elnora-mcp-server (the Elnora MCP server), elnora-plugins (the Elnora plugin marketplace), homebrew-cli (the Homebrew tap for the CLI).