Skip to content

Commit 4ddf2d4

Browse files
ckivisild-elnora-aiElnora AIclaude
authored
ci: add gitleaks secret scan, PR-title lint, and agent install docs (#26)
Bring elnora-plugins to CI/security/docs parity with the other public Elnora repos: - .github/workflows/gitleaks.yml + .gitleaks.toml — full-history secret scan using the open-source gitleaks binary (no org license required), on push/PR to main. Local full-history scan is clean. - .github/workflows/pr-title.yml — Conventional Commit lint on PR titles. - AGENTS.md — usage conventions for non-Claude agent harnesses: MCP endpoint, elnora_* tool dispatch table, pitfalls, per-harness install. - INSTALL_FOR_AGENTS.md — gated setup runbook (verify → auth → skills → smoke test) with Chrome DevTools MCP browser-assist offers for the OAuth and API-key browser steps. - README.md — link both agent docs. Claude-Session: https://claude.ai/code/session_01EgHf9qf7dcDzguCkqGRJzz Co-authored-by: Elnora AI <opensource@elnora.ai> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 9cecb27 commit 4ddf2d4

6 files changed

Lines changed: 402 additions & 0 deletions

File tree

.github/workflows/gitleaks.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Secret Scan (gitleaks)
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: gitleaks-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
gitleaks:
19+
name: gitleaks
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v7
23+
with:
24+
fetch-depth: 0
25+
- name: Install gitleaks
26+
env:
27+
GITLEAKS_VERSION: "8.21.2"
28+
run: |
29+
curl -sSfL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
30+
| tar -xz -C "$RUNNER_TEMP" gitleaks
31+
sudo install "$RUNNER_TEMP/gitleaks" /usr/local/bin/gitleaks
32+
gitleaks version
33+
# Uses the open-source gitleaks binary directly (no org license required,
34+
# unlike gitleaks-action). Scans the full git history for committed secrets.
35+
- name: Scan git history
36+
run: gitleaks detect --source . --config .gitleaks.toml --redact --verbose --exit-code 1

.github/workflows/pr-title.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# WARNING: this workflow uses `pull_request_target`, which runs in the context
2+
# of the BASE repo with access to secrets, even when triggered by a fork PR.
3+
# It currently only reads the PR title (a sanitized string) and does not check
4+
# out the PR head, so it is safe as written.
5+
#
6+
# Do NOT add `actions/checkout` here without pinning `ref` to the BASE sha,
7+
# and do NOT execute any code from the PR head — that would expose repository
8+
# secrets to fork authors. If you need to run code from the PR, use a
9+
# `pull_request` trigger in a separate workflow file instead.
10+
11+
name: PR Title Lint
12+
13+
on:
14+
pull_request_target:
15+
types: [opened, edited, synchronize]
16+
17+
permissions:
18+
pull-requests: read
19+
20+
jobs:
21+
lint:
22+
name: Conventional Commit
23+
runs-on: ubuntu-latest
24+
steps:
25+
- uses: amannn/action-semantic-pull-request@v6
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
with:
29+
types: |
30+
feat
31+
fix
32+
chore
33+
docs
34+
ci
35+
refactor
36+
perf
37+
test
38+
revert
39+
build
40+
requireScope: false
41+
subjectPattern: ^.+$
42+
subjectPatternError: "PR title must not be empty after the type prefix."

.gitleaks.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# gitleaks config for elnora-plugins.
2+
# Extend the built-in ruleset. This repository ships client-side plugin
3+
# configuration and Agent Skills only — no source secrets and no vendored
4+
# files with token-shaped example strings — so there is nothing to allow-list.
5+
# Add a [[rules.allowlist]] path here if that ever changes.
6+
[extend]
7+
useDefault = true

AGENTS.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# AGENTS.md
2+
3+
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).
4+
5+
## What this is
6+
7+
`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.
8+
9+
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).
10+
11+
## Setup
12+
13+
Every platform needs two things: (1) the MCP server connection and (2) the skill files copied into your tool's skills directory.
14+
15+
MCP config — use wherever your platform expects MCP server definitions:
16+
17+
```json
18+
{ "mcpServers": { "elnora": { "type": "http", "url": "https://mcp.elnora.ai/mcp" } } }
19+
```
20+
21+
Skills:
22+
23+
```sh
24+
cp -r elnora/skills/* <your-tool-skills-dir>/ # e.g. .cursor/skills, .codex/skills, .vscode/skills, .gemini/skills
25+
```
26+
27+
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).
28+
29+
## Dispatch — which skill for what
30+
31+
| User intent | Skill | Representative MCP tools |
32+
|---|---|---|
33+
| Generate / iterate a protocol; manage tasks + messages | `elnora-tasks` | `elnora_tasks_create`, `elnora_tasks_send`, `elnora_protocols_generate` |
34+
| Projects — list, create, members | `elnora-projects` | `elnora_projects_list` |
35+
| Files — list, read, upload, version, fork/promote, working copies | `elnora-files` | `elnora_files_list`, `elnora_files_content`, `elnora_files_upload`, `elnora_files_version` |
36+
| Folders / knowledge-base tree | `elnora-folders` | `elnora_folders_list`, `elnora_folders_create`, `elnora_folders_move` |
37+
| Search tasks / files / everything by keyword | `elnora-search` | `elnora_files_search` |
38+
| Organizations, members, invitations, billing, shared library | `elnora-orgs` | `elnora_orgs_get`, `elnora_orgs_invite`, `elnora_library_files` |
39+
| Auth, API keys, health, account, audit log, feature flags, agreements | `elnora-admin` | `elnora_health_check`, `elnora_account_get`, `elnora_audit_list`, `elnora_flags_list` |
40+
| Scientific tools + literature (PubMed / ArXiv / web) via the cloud agent | `elnora-agent` | `elnora_ask_agent` |
41+
| General "how do I use Elnora" / routing | `elnora-platform` | routes to the domain skill above |
42+
43+
A read-only `elnora_health_check` proves the MCP connection; `elnora_account_get` or `elnora_projects_list` proves auth works.
44+
45+
## Pitfalls
46+
47+
- **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.
48+
- **Skill dir must match `name`.** A skill's directory name must equal the `name:` in its `SKILL.md` frontmatter — CI (`Validate Skills`) fails otherwise.
49+
- **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.
50+
- **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.
51+
52+
## Safety
53+
54+
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.
55+
56+
## Claude Code
57+
58+
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):
59+
60+
```
61+
/plugin marketplace add https://github.com/Elnora-AI/elnora-plugins.git
62+
```
63+
64+
```
65+
/plugin install elnora@elnora-plugins
66+
```
67+
68+
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/).
69+
70+
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.
71+
72+
## Per-harness install
73+
74+
- **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/`.
75+
- **Cursor** — reads `AGENTS.md` natively. MCP in `.cursor/mcp.json`; `cp -r elnora/skills/* .cursor/skills/`.
76+
- **VS Code Copilot** — MCP in `.vscode/mcp.json`; `cp -r elnora/skills/* .vscode/skills/`.
77+
- **Gemini CLI** — MCP in your Gemini settings; `cp -r elnora/skills/* .gemini/skills/`.
78+
- **Continue / Amp / Jules / Roo** — read `AGENTS.md` at repo root automatically; add the MCP config per that tool's convention.
79+
80+
## Contributing to this repo
81+
82+
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`.
83+
84+
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`.

INSTALL_FOR_AGENTS.md

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# INSTALL_FOR_AGENTS.md — `elnora-plugins` setup
2+
3+
> **Step 0 — Identity gate.** If you are NOT an autonomous coding agent (Claude
4+
> Code, Codex CLI, Cursor, Aider, Continue, Amp, Jules, Roo, Windsurf, etc.),
5+
> stop reading this file and open `README.md` instead. This file walks an agent
6+
> through connecting the Elnora MCP server, authenticating (OAuth or an API key
7+
> you help the user create in a browser), copying the skill files, and running
8+
> a live smoke test against the Elnora Platform. Humans should follow the
9+
> README's Installation section.
10+
11+
You are the agent handing off after the user decided to install the Elnora
12+
plugin / MCP server. Your job: confirm the MCP connection is registered, get
13+
the user authenticated, make sure the 9 skills are where your harness reads
14+
them, run one read-only tool call to prove the stack works end to end, and hand
15+
back a working environment.
16+
17+
Be transparent: announce each step before you run it, show the output, and
18+
explain what you found. The user may not know what an MCP server or an Agent
19+
Skill is — keep the language plain and ask one question at a time. Never paste,
20+
echo, or commit an API key.
21+
22+
**Universal:** the MCP endpoint (`https://mcp.elnora.ai/mcp`) and the tool names
23+
(`elnora_*`) are identical under every harness. The only harness-specific parts
24+
are *where* the MCP server is registered and *where* skills are copied — the
25+
per-harness table in Step 3 covers that.
26+
27+
## Browser steps — offer to drive, don't assume
28+
29+
Two steps below happen in a web browser: completing OAuth (Step 2, option A)
30+
and creating an API key at `platform.elnora.ai` (Step 2, option B). How you
31+
handle them depends on what your harness can do:
32+
33+
- **If you have the Chrome DevTools MCP server available** (tools under
34+
`mcp__chrome-devtools__*`, e.g. Claude Code with it enabled): *offer* to open
35+
and drive the page for the user — "I can open `platform.elnora.ai` in your
36+
Chrome and walk the key-creation with you, or you can do it yourself and paste
37+
the result. Which do you prefer?" Only drive the browser if the user says yes.
38+
Never submit a login form or read back a secret without the user watching.
39+
- **If you do not have a browser-automation tool**, give the user the exact URL
40+
and click-path and wait for them to paste the result. Do not try to fetch an
41+
authenticated page yourself.
42+
43+
Either way the user stays in control of their own credentials.
44+
45+
## Step 1 — Verify the MCP connection is registered
46+
47+
The plugin declares the Elnora MCP server; a manual `mcp add` registers it
48+
directly. Confirm your harness sees a server named `elnora` pointed at
49+
`https://mcp.elnora.ai/mcp` before going further.
50+
51+
- **Claude Code (plugin path).** Confirm the plugin loaded:
52+
53+
```sh
54+
ls .claude/plugins 2>/dev/null || ls ~/.claude/plugins 2>/dev/null
55+
```
56+
57+
You should see `elnora` (or `elnora-plugins`) listed. If not, the
58+
`/plugin install elnora@elnora-plugins` didn't complete — ask the user to
59+
rerun it. You can also list MCP servers with `claude mcp list` and confirm an
60+
`elnora` entry appears.
61+
62+
- **Claude Code (API-key MCP path, no plugin).** Register it:
63+
64+
```sh
65+
claude mcp add elnora --transport http --scope user \
66+
https://mcp.elnora.ai/mcp \
67+
--header "X-API-Key: <key-from-Step-2>"
68+
```
69+
70+
If you register this AND enable the plugin, you'll have two servers both named
71+
`elnora` — keep one, not both.
72+
73+
- **Other harnesses (Codex / Cursor / VS Code Copilot / Gemini).** Confirm the
74+
MCP config block exists in the right file (see Step 3). There is no CLI to
75+
`--version` here — the check is "is the `elnora` server in my MCP config and
76+
does a tool call reach it," which Step 4 proves.
77+
78+
Gate: your harness lists an `elnora` MCP server. If it doesn't, stop and fix the
79+
registration before spending an auth round-trip.
80+
81+
## Step 2 — Authenticate
82+
83+
The Elnora MCP server accepts two auth methods. Ask the user which they want:
84+
85+
> Elnora authenticates two ways. (A) **OAuth** — recommended; a browser popup
86+
> opens on the first call, you click approve, and your client stores and
87+
> refreshes the token for you. Nothing to paste. (B) **API key** — better for
88+
> CI or non-interactive setups; you create a key once at platform.elnora.ai and
89+
> it's passed as a header. Which do you want?
90+
91+
### Option A — OAuth 2.1 (recommended)
92+
93+
No key handling. The first tool call (Step 4) triggers the browser popup
94+
automatically; the user approves once and the token is cached by their MCP
95+
client. There is nothing to persist in this repo.
96+
97+
- If you have the Chrome DevTools MCP server, you may *offer* to bring the
98+
approval page forward and confirm the redirect completes — but the user
99+
approves; you don't. If you don't have it, just tell the user "a browser
100+
window will open on the first Elnora call — approve it there," and continue.
101+
102+
Gate: none yet. OAuth is validated by the smoke test in Step 4 succeeding
103+
without a `401`.
104+
105+
### Option B — API key
106+
107+
1. **Create the key.** Tell the user, verbatim:
108+
109+
> Open https://platform.elnora.ai in your browser, go to account settings →
110+
> API keys, click **Create key**, name it something like "mcp-<harness>",
111+
> and copy the value. It starts with `elnora_live_`.
112+
113+
Follow the browser-step rules above: if you have Chrome DevTools MCP, offer
114+
to open the page and walk the click-path with the user watching; otherwise
115+
wait for them to paste the key.
116+
117+
2. **Store it in the client's secret store or an env var — never in this repo.**
118+
The key goes in your MCP client's header config (`X-API-Key` or
119+
`Authorization: Bearer <key>`), your OS keychain, or an environment variable.
120+
Do NOT write it into any file under the repository, a skill file, or a commit
121+
`.env` and `*.local` are gitignored precisely so a stray key can't be
122+
committed, but the safest place is the client secret store.
123+
124+
For Claude Code's API-key MCP path, the key is passed on the
125+
`claude mcp add` command from Step 1 (`--header "X-API-Key: <key>"`), which
126+
stores it in the user-scope MCP config, not in this repo.
127+
128+
Gate: the key is set in the client's auth config (verified by Step 4), starts
129+
with `elnora_live_`, and appears in NO file tracked by git. If the user pasted
130+
it into a chat or a repo file, tell them to rotate it.
131+
132+
## Step 3 — Register MCP + copy skills (non-Claude harnesses)
133+
134+
Claude Code users who installed the plugin can skip this — the plugin ships both
135+
the MCP declaration and the skills. Everyone else does both halves:
136+
137+
| Harness | MCP config file | Skills directory |
138+
|---|---|---|
139+
| Cursor | `.cursor/mcp.json` | `.cursor/skills/` |
140+
| OpenAI Codex | `codex mcp add elnora -- https://mcp.elnora.ai/mcp` | `.codex/skills/` |
141+
| VS Code Copilot | `.vscode/mcp.json` | `.vscode/skills/` |
142+
| Gemini CLI | Gemini settings | `.gemini/skills/` |
143+
| Generic MCP client | point at `https://mcp.elnora.ai/mcp` | your tool's skills dir |
144+
145+
MCP block for the JSON-config harnesses:
146+
147+
```json
148+
{ "mcpServers": { "elnora": { "type": "http", "url": "https://mcp.elnora.ai/mcp" } } }
149+
```
150+
151+
Copy the skills:
152+
153+
```sh
154+
cp -r elnora/skills/* <skills-dir>/
155+
```
156+
157+
Gate: all 9 skill directories (`elnora-platform`, `elnora-orgs`,
158+
`elnora-projects`, `elnora-tasks`, `elnora-files`, `elnora-folders`,
159+
`elnora-search`, `elnora-admin`, `elnora-agent`) landed in the target dir, each
160+
containing a `SKILL.md`.
161+
162+
## Step 4 — Smoke test
163+
164+
Two tool calls, in order. The first needs no auth; the second proves auth works.
165+
166+
1. **Liveness.** Call `elnora_health_check` (via the `elnora-admin` /
167+
`elnora-platform` skill, or the raw MCP tool).
168+
169+
Gate: it returns a healthy status. A transport error here means the MCP
170+
server isn't registered — go back to Step 1. This call does not prove auth.
171+
172+
2. **Authenticated read.** Call `elnora_account_get` (whoami) or
173+
`elnora_projects_list`.
174+
175+
Gates:
176+
- **OAuth (Option A):** the first call opens the approval popup. After the
177+
user approves, the call returns account/project data. If it keeps failing
178+
with `401`, the OAuth flow didn't complete — have the user re-approve.
179+
- **API key (Option B):** the call returns data immediately. A `401` means
180+
the key is wrong or not reaching the header — re-check Step 2. Do NOT retry
181+
with a key you guessed or reconstructed; ask the user to paste it again or
182+
regenerate it.
183+
- An empty projects list is a valid result (a new account may have none) —
184+
distinguish "empty, exit ok" from "error."
185+
186+
If you have the Chrome DevTools MCP server and OAuth stalls, you may offer to
187+
bring the approval tab forward so the user can complete it — but they click
188+
approve, not you.
189+
190+
## Step 5 — Handoff summary
191+
192+
Tell the user, in this order:
193+
194+
1. **What's connected** — the `elnora` MCP server at
195+
`https://mcp.elnora.ai/mcp`, and (non-Claude harnesses) where the 9 skills
196+
were copied.
197+
2. **How they're authenticated** — OAuth (token cached by their client) or API
198+
key (stored in the client's secret store / header config). If API key, remind
199+
them it's never stored in this repo and to rotate it if it ever leaks.
200+
3. **How to use it** — one entry point that matches the harness:
201+
- **Claude Code with the plugin:** `/elnora:protocol <description>`, or just
202+
ask in natural language ("use Elnora to list my projects").
203+
- **Any other harness:** ask in natural language; the skills route the intent
204+
to the right `elnora_*` MCP tool. Dispatch table in [`AGENTS.md`](AGENTS.md).
205+
4. **Where auth lives** — their MCP client's config / secret store, never this
206+
repo.
207+
208+
## Completion checklist
209+
210+
Verify ALL of these before declaring done. If any fails, finish it first.
211+
212+
1. The harness lists an `elnora` MCP server pointed at
213+
`https://mcp.elnora.ai/mcp`.
214+
2. `elnora_health_check` returns a healthy status.
215+
3. `elnora_account_get` (or `elnora_projects_list`) returns data — no `401`
216+
(empty project list is OK; an auth error is not).
217+
4. **Non-Claude harnesses:** all 9 skill directories are present in the target
218+
skills dir, each with a `SKILL.md`.
219+
5. If the user chose the API key: it is set in the client's auth config, and it
220+
appears in NO git-tracked file. You did not echo it into chat or a repo file.
221+
6. You wrote nothing to the repository that the user didn't ask for — no keys,
222+
no local config committed.
223+
224+
When all applicable items pass, print `ELNORA_PLUGINS_READY` on its own line so
225+
the user (and any wrapping harness) can grep for it.

0 commit comments

Comments
 (0)