Skip to content

Run Your Own Agora

nitekeeper edited this page Jun 24, 2026 · 4 revisions

Run Your Own Agora

Heads up — Agora is not accepting third-party plugins at this time. The canonical nitekeeper/agora marketplace indexes only the maintainer-curated set (atelier, memex, agora, loom-agent-chat). To index your own plugins, run your own Agora instance by forking or cloning it. Please don't open plugin-registration PRs against nitekeeper/agora right now — they won't be reviewed. Everything below shows you how to stand up an instance you fully control.

This page teaches the self-host model. If you only want to install the four maintainer-curated plugins from the canonical marketplace, you don't need any of this — see Register Agora in Claude Code for that UI flow. Self-hosting is required only when you want to index your own plugins.

Why run your own instance

Agora is built to be forked — its own README states plainly that "Forks are expected." Agora is a pure indexer: it never edits the plugin repos it points at, and it stores all of its state in two files in its own repo (plugins.json + the compiled .claude-plugin/marketplace.json). That makes a fork completely self-contained.

Running your own instance gives you:

  • A private or curated marketplace you fully own — index exactly the plugins you want, public or internal.
  • Full control of policy and workflow — your repo, your branch rules, your release cadence.
  • Distribution on your terms — keep it local-only, or push your fork and let your team add it as a marketplace.

Prerequisites

Prerequisites: Agora's scripts call out to local tooling and the GitHub API, and they fail loudly with a remediation hint if anything is missing.

  • git on your PATH.
  • gh CLI, authenticated — gh auth status must exit 0 (license detection, semver discovery, and metadata reads all hit the GitHub API).
  • Python 3.11+, with pip install -r requirements.txt applied from the agora repo root.
  • The plugin you want to index must be a GitHub repository. The register step reads tags, the LICENSE, the description, and topics through the GitHub API — a non-GitHub repo cannot be indexed.

Set up your instance

1. Fork (to distribute) or clone (for local-only use).

If you plan to share your marketplace with others, fork agora on GitHub first, then clone your fork. For purely local use you can clone directly.

# clone your fork
git clone https://github.com/<you>/agora.git

2. Install dependencies from the repo root.

pip install -r requirements.txt

3. Bootstrap with setup.py.

python3 scripts/setup.py

This does two things:

  • Registers your local checkout as a marketplace in ~/.claude/settings.json as a directory pointer — it writes extraKnownMarketplaces.agora = {"source": "directory", "path": "<your local checkout>"}. That means Claude Code reads the marketplace straight from your working tree on disk.
  • Compiles marketplace.json from plugins.json so the generated artifact is fresh.

setup.py is interactive — it prints the planned change to ~/.claude/settings.json and prompts Apply changes? [y/N]:. Pass --yes (or -y) to skip the prompt:

python3 scripts/setup.py --yes

Note: Setup is narrow on purpose. It only writes the directory pointer and compiles marketplace.json. It does not validate registry entries and does not install any session hook or banner. It backs up your existing settings.json before writing.

Prepare the plugin you want to index

Agora derives every field of a registry entry from the plugin's GitHub repo — there are no agora-specific files to add to your plugin. Make sure the repo has:

  • A LICENSE file with a recognized SPDX identifier (MIT, Apache-2.0, BSD-3-Clause, …). Required. If neither a local LICENSE nor the GitHub API yields a recognized SPDX id, registration fails with a hard error. There is no way to weaken this gate.

  • A non-empty GitHub repo description. Agora uses it verbatim as the plugin description. An empty description is a hard error (not a prompt) — set it on GitHub, or pass --description '...' at register time.

  • GitHub topics (optional, recommended). Agora maps them against its taxonomy to derive category and keywords.

  • A plugin.json following Claude Code's plugin schema. Claude Code reads this after a consumer installs your plugin — agora itself never parses it.

  • At least one stable SemVer release tag:

    git tag vX.Y.Z
    git push --tags

Note: Pre-release tags (-rc, -beta, -alpha) are skipped by default. A repo whose only tags are pre-release fails registration with a clear error. To index a pre-release, pass --include-prerelease explicitly — the stable-only default mirrors npm, cargo, and pip.

Register the plugin into your instance

From your agora checkout, invoke the agora:run skill and describe your intent in natural language — for example, "register a plugin". There are no agora:<verb> slash commands; agora:run is the single skill, and it routes to the internal plugin-register operation, which works in either of two modes:

  • Auto-detect from the current directory. Run it with your plugin repo as the current directory. The operation reads git remote get-url origin to discover the URL automatically.
  • By URL (no clone needed). Tell it the repo URL — for example, "register the plugin at https://github.com/<owner>/<repo>.git".

The equivalent CLI invocations, run from your agora repo root:

# cwd = your plugin repo (origin URL auto-detected):
python3 scripts/plugin_register.py

# explicit URL (any cwd):
python3 scripts/plugin_register.py --url https://github.com/<owner>/<repo>.git

# allow a pre-release when no stable tag exists yet:
python3 scripts/plugin_register.py --url https://github.com/<owner>/<repo>.git --include-prerelease

# override the derived description or category:
python3 scripts/plugin_register.py --url https://github.com/<owner>/<repo>.git \
  --description "Short tagline" --category development

Registration is idempotent: re-running on an already-registered plugin refreshes its version and metadata in place (no duplicate), preserving the original registered_at.

Note: This writes your plugins.json and atomically recompiles your .claude-plugin/marketplace.json in the same operation — both files land together or neither does (via scripts/atomic.py). Never hand-edit marketplace.json; it's a generated artifact, rebuilt on every write.

On failure (missing license, empty GitHub description, no stable tags, GitHub API error, malformed URL) the operation writes a one-line error to stderr and exits 1 — fix the cause and re-run.

Commit to your fork

This is your instance, so you set the workflow. Commit the updated plugins.json and marketplace.json to your main, or use a branch + PR — whatever suits your team.

Note: Agora's "no direct commit to main / PR-only" rule binds the canonical nitekeeper/agora repo's contributors, not your fork. In your own instance, branch protection is your call.

git add plugins.json .claude-plugin/marketplace.json
git commit -m "Register <repo> vX.Y.Z"

Use it / share it

Use it yourself. Reload so your own Claude Code picks up the new entry — restart Claude Code or run /reload-plugins, then open /plugin > Marketplaces > agora to browse and install. Because your marketplace is a directory pointer at your local checkout, your committed (or even just-written) marketplace.json is read straight from disk.

Share it with others. Push your fork to GitHub. Your consumers then add your marketplace by its URLhttps://github.com/<you>/agora — via /plugin > + Add Marketplace. That is the same UI flow documented in Register Agora in Claude Code; just substitute your fork's URL for the canonical one. When you ship new plugin versions, consumers refresh by pressing u to update on the Marketplaces tab.

Optional — avoid a name collision. If you'll distribute your fork and your consumers might also use the canonical agora, edit the top-level marketplace object in plugins.json (name, description, owner) so your instance carries its own marketplace name and doesn't collide with agora. That object seeds the marketplace-level fields in the compiled marketplace.json.

How agora fills in your entry

You maintain no agora-specific files. Agora derives every plugins.json field from the plugin's git repo and the GitHub API:

Field Sourced from
name URL path → <repo>, lowercased and bare (owner dropped, .git stripped)
repository_url The repo URL
current_version Latest stable git tag
current_sha Tag resolved to its commit SHA
description GitHub repo description. Hard error if empty — set it on GitHub or pass --description.
license LICENSE file (SPDX-parsed); GitHub API fallback. Hard error if not detected.
category, keywords GitHub topics, mapped against agora's taxonomy
author Repo owner, parsed from the URL path, stored as {"name": <owner>}
homepage GitHub API (falls back to https://github.com/<owner>/<repo>)

Plugin naming

Plugin entries use the bare, lowercase repo name — the owner is dropped and any .git suffix is stripped.

Example: github.com/<you>/atelier → plugin name atelier (not <you>-atelier).

Names must be lowercase alphanumeric plus dot and dash. Agora stores the source git URL as the real anchor, so the bare name is just the display identifier. (Because the owner is dropped, two repos with the same name from different owners would collide within a single instance.)


Home · Register Agora in Claude Code

Clone this wiki locally