Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/gitleaks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: Secret Scan (gitleaks)

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: gitleaks-${{ github.ref }}
cancel-in-progress: true

jobs:
gitleaks:
name: gitleaks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Install gitleaks
env:
GITLEAKS_VERSION: "8.21.2"
run: |
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| tar -xz -C "$RUNNER_TEMP" gitleaks
sudo install "$RUNNER_TEMP/gitleaks" /usr/local/bin/gitleaks
gitleaks version
# Uses the open-source gitleaks binary directly (no org license required,
# unlike gitleaks-action). Scans the full git history for committed secrets.
- name: Scan git history
run: gitleaks detect --source . --config .gitleaks.toml --redact --verbose --exit-code 1
42 changes: 42 additions & 0 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# WARNING: this workflow uses `pull_request_target`, which runs in the context
# of the BASE repo with access to secrets, even when triggered by a fork PR.
# It currently only reads the PR title (a sanitized string) and does not check
# out the PR head, so it is safe as written.
#
# Do NOT add `actions/checkout` here without pinning `ref` to the BASE sha,
# and do NOT execute any code from the PR head — that would expose repository
# secrets to fork authors. If you need to run code from the PR, use a
# `pull_request` trigger in a separate workflow file instead.

name: PR Title Lint

on:
pull_request_target:
types: [opened, edited, synchronize]

permissions:
pull-requests: read

jobs:
lint:
name: Conventional Commit
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v6

Check warning

Code scanning / CodeQL

Unpinned tag for a non-immutable Action in workflow or composite action Medium

Unpinned 3rd party Action 'PR Title Lint' step
Uses Step
uses 'amannn/action-semantic-pull-request' with ref 'v6', not a pinned commit hash
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
feat
fix
chore
docs
ci
refactor
perf
test
revert
build
requireScope: false
subjectPattern: ^.+$
subjectPatternError: "PR title must not be empty after the type prefix."
7 changes: 7 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# gitleaks config for elnora-plugins.
# Extend the built-in ruleset. This repository ships client-side plugin
# configuration and Agent Skills only — no source secrets and no vendored
# files with token-shaped example strings — so there is nothing to allow-list.
# Add a [[rules.allowlist]] path here if that ever changes.
[extend]
useDefault = true
84 changes: 84 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# AGENTS.md

Universal guide for any coding agent working with `elnora-plugins`. Read natively by Codex, Cursor, Aider, Continue, Amp, Jules, and Roo. Claude Code reads `CLAUDE.md` instead — but note this repo's `CLAUDE.md` is the marketplace-maintainer guide, not a copy of this file (see [Claude Code](#claude-code) below).

## What this is

`elnora-plugins` is the Elnora AI plugins marketplace: one Claude Code plugin (`elnora`) bundling **9 Agent Skills** plus an **MCP server declaration** for the Elnora AI Platform at `https://mcp.elnora.ai/mcp`. It ships client-side configuration only — no CLI in this repo, no server code, no credentials. Agents drive the platform by invoking the Elnora MCP tools; the skills tell you which tool serves which intent.

Every skill routes to MCP tools named `elnora_*` (e.g. `elnora_health_check`, `elnora_projects_list`, `elnora_tasks_create`). Under a namespaced MCP client the same tools surface as `elnora__elnora_*` (or `mcp__elnora__elnora_*` in Claude Code).

## Setup

Every platform needs two things: (1) the MCP server connection and (2) the skill files copied into your tool's skills directory.

MCP config — use wherever your platform expects MCP server definitions:

```json
{ "mcpServers": { "elnora": { "type": "http", "url": "https://mcp.elnora.ai/mcp" } } }
```

Skills:

```sh
cp -r elnora/skills/* <your-tool-skills-dir>/ # e.g. .cursor/skills, .codex/skills, .vscode/skills, .gemini/skills
```

Authentication happens on the first MCP call — OAuth 2.1 (browser popup, recommended) or an API key generated at `platform.elnora.ai`. For a guided, gated walkthrough (verify → auth → smoke test), point your agent at [`INSTALL_FOR_AGENTS.md`](INSTALL_FOR_AGENTS.md).

## Dispatch — which skill for what

| User intent | Skill | Representative MCP tools |
|---|---|---|
| Generate / iterate a protocol; manage tasks + messages | `elnora-tasks` | `elnora_tasks_create`, `elnora_tasks_send`, `elnora_protocols_generate` |
| Projects — list, create, members | `elnora-projects` | `elnora_projects_list` |
| Files — list, read, upload, version, fork/promote, working copies | `elnora-files` | `elnora_files_list`, `elnora_files_content`, `elnora_files_upload`, `elnora_files_version` |
| Folders / knowledge-base tree | `elnora-folders` | `elnora_folders_list`, `elnora_folders_create`, `elnora_folders_move` |
| Search tasks / files / everything by keyword | `elnora-search` | `elnora_files_search` |
| Organizations, members, invitations, billing, shared library | `elnora-orgs` | `elnora_orgs_get`, `elnora_orgs_invite`, `elnora_library_files` |
| Auth, API keys, health, account, audit log, feature flags, agreements | `elnora-admin` | `elnora_health_check`, `elnora_account_get`, `elnora_audit_list`, `elnora_flags_list` |
| Scientific tools + literature (PubMed / ArXiv / web) via the cloud agent | `elnora-agent` | `elnora_ask_agent` |
| General "how do I use Elnora" / routing | `elnora-platform` | routes to the domain skill above |

A read-only `elnora_health_check` proves the MCP connection; `elnora_account_get` or `elnora_projects_list` proves auth works.

## Pitfalls

- **MCP-only.** This repo references no CLI commands inside skills — every skill maps to an `elnora_*` MCP tool. Keep it that way when editing skills.
- **Skill dir must match `name`.** A skill's directory name must equal the `name:` in its `SKILL.md` frontmatter — CI (`Validate Skills`) fails otherwise.
- **Two "elnora" servers.** If you register the API-key MCP manually (`claude mcp add elnora …`) AND enable the plugin, you get two servers both named `elnora`. Use one, not both.
- **OAuth is per-client.** Tokens are stored and refreshed by your MCP client, never by files in this repo. There is nothing to persist here.

## Safety

Client-side config + skills only; no secrets in-repo. `.env` and `*.local` files are gitignored, and secret scanning (`gitleaks`) plus CodeQL run on every PR. Agent Skills execute in your tool's context — only install marketplaces you trust and review skill files before running them in a privileged environment. Report vulnerabilities privately per [`.github/SECURITY.md`](.github/SECURITY.md) (security@elnora.ai) — do not open a public issue.

## Claude Code

The plugin provides a native slash command, the 9 skills, and the MCP declaration. Install as **two separate slash commands** (paste the first, wait for it to finish, then paste the second):

```
/plugin marketplace add https://github.com/Elnora-AI/elnora-plugins.git
```

```
/plugin install elnora@elnora-plugins
```

Surface: `/elnora:protocol <description>` generates a bioprotocol; the 9 skills auto-load and route by intent. Definitions live in [`elnora/commands/`](elnora/commands/) and [`elnora/skills/`](elnora/skills/).

This repo already ships a `CLAUDE.md`, but it is the **marketplace-maintainer** guide (structure, skill spec, how to add a plugin) — a different audience from this file. Do **not** `ln -s AGENTS.md CLAUDE.md` here; the two are intentionally distinct.

## Per-harness install

- **Codex CLI** — `AGENTS.md` is auto-loaded at repo root. `codex mcp add elnora -- https://mcp.elnora.ai/mcp`, then `cp -r elnora/skills/* .codex/skills/`.
- **Cursor** — reads `AGENTS.md` natively. MCP in `.cursor/mcp.json`; `cp -r elnora/skills/* .cursor/skills/`.
- **VS Code Copilot** — MCP in `.vscode/mcp.json`; `cp -r elnora/skills/* .vscode/skills/`.
- **Gemini CLI** — MCP in your Gemini settings; `cp -r elnora/skills/* .gemini/skills/`.
- **Continue / Amp / Jules / Roo** — read `AGENTS.md` at repo root automatically; add the MCP config per that tool's convention.

## Contributing to this repo

Skill spec (agentskills.io): `name` is lowercase letters/digits/hyphens, ≤64 chars; `description` ≤1024 chars; body under 500 lines; the directory name matches the frontmatter `name`. Register new plugins in `.claude-plugin/marketplace.json`.

CI on every PR: `Validate Skills` (manifest + frontmatter checks), CodeQL (`actions`), and `gitleaks` secret scan. PR titles must be Conventional Commits — `feat`, `fix`, `chore`, `docs`, `ci`, `refactor`, `perf`, `test`, `revert`, `build`.
225 changes: 225 additions & 0 deletions INSTALL_FOR_AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
# INSTALL_FOR_AGENTS.md — `elnora-plugins` setup

> **Step 0 — Identity gate.** If you are NOT an autonomous coding agent (Claude
> Code, Codex CLI, Cursor, Aider, Continue, Amp, Jules, Roo, Windsurf, etc.),
> stop reading this file and open `README.md` instead. This file walks an agent
> through connecting the Elnora MCP server, authenticating (OAuth or an API key
> you help the user create in a browser), copying the skill files, and running
> a live smoke test against the Elnora Platform. Humans should follow the
> README's Installation section.

You are the agent handing off after the user decided to install the Elnora
plugin / MCP server. Your job: confirm the MCP connection is registered, get
the user authenticated, make sure the 9 skills are where your harness reads
them, run one read-only tool call to prove the stack works end to end, and hand
back a working environment.

Be transparent: announce each step before you run it, show the output, and
explain what you found. The user may not know what an MCP server or an Agent
Skill is — keep the language plain and ask one question at a time. Never paste,
echo, or commit an API key.

**Universal:** the MCP endpoint (`https://mcp.elnora.ai/mcp`) and the tool names
(`elnora_*`) are identical under every harness. The only harness-specific parts
are *where* the MCP server is registered and *where* skills are copied — the
per-harness table in Step 3 covers that.

## Browser steps — offer to drive, don't assume

Two steps below happen in a web browser: completing OAuth (Step 2, option A)
and creating an API key at `platform.elnora.ai` (Step 2, option B). How you
handle them depends on what your harness can do:

- **If you have the Chrome DevTools MCP server available** (tools under
`mcp__chrome-devtools__*`, e.g. Claude Code with it enabled): *offer* to open
and drive the page for the user — "I can open `platform.elnora.ai` in your
Chrome and walk the key-creation with you, or you can do it yourself and paste
the result. Which do you prefer?" Only drive the browser if the user says yes.
Never submit a login form or read back a secret without the user watching.
- **If you do not have a browser-automation tool**, give the user the exact URL
and click-path and wait for them to paste the result. Do not try to fetch an
authenticated page yourself.

Either way the user stays in control of their own credentials.

## Step 1 — Verify the MCP connection is registered

The plugin declares the Elnora MCP server; a manual `mcp add` registers it
directly. Confirm your harness sees a server named `elnora` pointed at
`https://mcp.elnora.ai/mcp` before going further.

- **Claude Code (plugin path).** Confirm the plugin loaded:

```sh
ls .claude/plugins 2>/dev/null || ls ~/.claude/plugins 2>/dev/null
```

You should see `elnora` (or `elnora-plugins`) listed. If not, the
`/plugin install elnora@elnora-plugins` didn't complete — ask the user to
rerun it. You can also list MCP servers with `claude mcp list` and confirm an
`elnora` entry appears.

- **Claude Code (API-key MCP path, no plugin).** Register it:

```sh
claude mcp add elnora --transport http --scope user \
https://mcp.elnora.ai/mcp \
--header "X-API-Key: <key-from-Step-2>"
```

If you register this AND enable the plugin, you'll have two servers both named
`elnora` — keep one, not both.

- **Other harnesses (Codex / Cursor / VS Code Copilot / Gemini).** Confirm the
MCP config block exists in the right file (see Step 3). There is no CLI to
`--version` here — the check is "is the `elnora` server in my MCP config and
does a tool call reach it," which Step 4 proves.

Gate: your harness lists an `elnora` MCP server. If it doesn't, stop and fix the
registration before spending an auth round-trip.

## Step 2 — Authenticate

The Elnora MCP server accepts two auth methods. Ask the user which they want:

> Elnora authenticates two ways. (A) **OAuth** — recommended; a browser popup
> opens on the first call, you click approve, and your client stores and
> refreshes the token for you. Nothing to paste. (B) **API key** — better for
> CI or non-interactive setups; you create a key once at platform.elnora.ai and
> it's passed as a header. Which do you want?

### Option A — OAuth 2.1 (recommended)

No key handling. The first tool call (Step 4) triggers the browser popup
automatically; the user approves once and the token is cached by their MCP
client. There is nothing to persist in this repo.

- If you have the Chrome DevTools MCP server, you may *offer* to bring the
approval page forward and confirm the redirect completes — but the user
approves; you don't. If you don't have it, just tell the user "a browser
window will open on the first Elnora call — approve it there," and continue.

Gate: none yet. OAuth is validated by the smoke test in Step 4 succeeding
without a `401`.

### Option B — API key

1. **Create the key.** Tell the user, verbatim:

> Open https://platform.elnora.ai in your browser, go to account settings →
> API keys, click **Create key**, name it something like "mcp-<harness>",
> and copy the value. It starts with `elnora_live_`.

Follow the browser-step rules above: if you have Chrome DevTools MCP, offer
to open the page and walk the click-path with the user watching; otherwise
wait for them to paste the key.

2. **Store it in the client's secret store or an env var — never in this repo.**
The key goes in your MCP client's header config (`X-API-Key` or
`Authorization: Bearer <key>`), your OS keychain, or an environment variable.
Do NOT write it into any file under the repository, a skill file, or a commit
— `.env` and `*.local` are gitignored precisely so a stray key can't be
committed, but the safest place is the client secret store.

For Claude Code's API-key MCP path, the key is passed on the
`claude mcp add` command from Step 1 (`--header "X-API-Key: <key>"`), which
stores it in the user-scope MCP config, not in this repo.

Gate: the key is set in the client's auth config (verified by Step 4), starts
with `elnora_live_`, and appears in NO file tracked by git. If the user pasted
it into a chat or a repo file, tell them to rotate it.

## Step 3 — Register MCP + copy skills (non-Claude harnesses)

Claude Code users who installed the plugin can skip this — the plugin ships both
the MCP declaration and the skills. Everyone else does both halves:

| Harness | MCP config file | Skills directory |
|---|---|---|
| Cursor | `.cursor/mcp.json` | `.cursor/skills/` |
| OpenAI Codex | `codex mcp add elnora -- https://mcp.elnora.ai/mcp` | `.codex/skills/` |
| VS Code Copilot | `.vscode/mcp.json` | `.vscode/skills/` |
| Gemini CLI | Gemini settings | `.gemini/skills/` |
| Generic MCP client | point at `https://mcp.elnora.ai/mcp` | your tool's skills dir |

MCP block for the JSON-config harnesses:

```json
{ "mcpServers": { "elnora": { "type": "http", "url": "https://mcp.elnora.ai/mcp" } } }
```

Copy the skills:

```sh
cp -r elnora/skills/* <skills-dir>/
```

Gate: all 9 skill directories (`elnora-platform`, `elnora-orgs`,
`elnora-projects`, `elnora-tasks`, `elnora-files`, `elnora-folders`,
`elnora-search`, `elnora-admin`, `elnora-agent`) landed in the target dir, each
containing a `SKILL.md`.

## Step 4 — Smoke test

Two tool calls, in order. The first needs no auth; the second proves auth works.

1. **Liveness.** Call `elnora_health_check` (via the `elnora-admin` /
`elnora-platform` skill, or the raw MCP tool).

Gate: it returns a healthy status. A transport error here means the MCP
server isn't registered — go back to Step 1. This call does not prove auth.

2. **Authenticated read.** Call `elnora_account_get` (whoami) or
`elnora_projects_list`.

Gates:
- **OAuth (Option A):** the first call opens the approval popup. After the
user approves, the call returns account/project data. If it keeps failing
with `401`, the OAuth flow didn't complete — have the user re-approve.
- **API key (Option B):** the call returns data immediately. A `401` means
the key is wrong or not reaching the header — re-check Step 2. Do NOT retry
with a key you guessed or reconstructed; ask the user to paste it again or
regenerate it.
- An empty projects list is a valid result (a new account may have none) —
distinguish "empty, exit ok" from "error."

If you have the Chrome DevTools MCP server and OAuth stalls, you may offer to
bring the approval tab forward so the user can complete it — but they click
approve, not you.

## Step 5 — Handoff summary

Tell the user, in this order:

1. **What's connected** — the `elnora` MCP server at
`https://mcp.elnora.ai/mcp`, and (non-Claude harnesses) where the 9 skills
were copied.
2. **How they're authenticated** — OAuth (token cached by their client) or API
key (stored in the client's secret store / header config). If API key, remind
them it's never stored in this repo and to rotate it if it ever leaks.
3. **How to use it** — one entry point that matches the harness:
- **Claude Code with the plugin:** `/elnora:protocol <description>`, or just
ask in natural language ("use Elnora to list my projects").
- **Any other harness:** ask in natural language; the skills route the intent
to the right `elnora_*` MCP tool. Dispatch table in [`AGENTS.md`](AGENTS.md).
4. **Where auth lives** — their MCP client's config / secret store, never this
repo.

## Completion checklist

Verify ALL of these before declaring done. If any fails, finish it first.

1. The harness lists an `elnora` MCP server pointed at
`https://mcp.elnora.ai/mcp`.
2. `elnora_health_check` returns a healthy status.
3. `elnora_account_get` (or `elnora_projects_list`) returns data — no `401`
(empty project list is OK; an auth error is not).
4. **Non-Claude harnesses:** all 9 skill directories are present in the target
skills dir, each with a `SKILL.md`.
5. If the user chose the API key: it is set in the client's auth config, and it
appears in NO git-tracked file. You did not echo it into chat or a repo file.
6. You wrote nothing to the repository that the user didn't ask for — no keys,
no local config committed.

When all applicable items pass, print `ELNORA_PLUGINS_READY` on its own line so
the user (and any wrapping harness) can grep for it.
Loading