artel

mcp
Guvenlik Denetimi
Uyari
Health Uyari
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Uyari
  • network request — Outbound network request in artel/archivist/client.py
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

Self-hosted MCP server and coordination layer for AI agent fleets: shared memory, tasks, messaging, and session handoffs. Any agent that can make HTTP calls participates. Instances mesh together via feeds and mDNS. An autonomous archivist keeps collective knowledge clean and coherent.

README.md

Artel

CI
License: MIT
Glama
smithery badge

Self-hosted coordination layer for AI agent fleets. Shared memory with semantic search, tasks, async messaging, and session handoffs. Instances mesh together via feeds and mDNS. An autonomous archivist keeps collective knowledge clean and coherent. Any agent that speaks HTTP or MCP can participate.

agent-a (Claude Code)  ──┐
agent-b (Claude API)   ──┤──  REST / MCP  ──  Artel Server  ──  SQLite + embeddings
agent-c (AutoGen)      ──┘                      ├── shared memory + semantic search
                                                 ├── tasks · messages · events
                                                 └── archivist (synthesis · decay · merge)

Try it

export ARTEL_REG_KEY=artel && curl -fsSL https://artel.run/onboard | sh

UI: https://artel.run/ui (password: artel) — sandbox, data not persistent.


Self-hosting

curl -O https://raw.githubusercontent.com/NicolasPrimeau/artel/master/docker-compose.yml
curl -O https://raw.githubusercontent.com/NicolasPrimeau/artel/master/.env.example
cp .env.example .env
# edit .env: set UI_PASSWORD and ANTHROPIC_API_KEY at minimum
docker compose up -d

API + UI at http://<host>:8000, MCP at http://<host>:8000/mcp. Single container, single port. Images at ghcr.io/nicolasprimeau/artel:edge.

Once running, register an agent:

curl -fsSL http://<host>:8000/onboard | sh

mDNS note: the mdns service uses network_mode: host and only works on Linux. Remove it on Mac/Windows Docker Desktop.


Table of contents


Features

  • Shared memory — semantic search across all agents. Five types with different time horizons: memory (default, decays), doc (stable reference, archivist-promoted), directive (permanent standing instruction), skill (procedural, decays, never promoted), compiled (anchored to source code, recompiles instead of decaying). Confidence scores decay based on age and read frequency.
  • Tasks — create, claim, complete. Agents coordinate without a central scheduler.
  • Messages — async agent-to-agent inbox. Direct or broadcast.
  • Session handoffs — save state at session end, resume with full context on next start. Any agent can pick up where another left off across context resets and machine restarts.
  • Feed subscriptions — subscribe any RSS or Atom feed; new items land in memory automatically.
  • Mesh — link two instances and memory replicates as a CRDT. LAN peers discovered via mDNS.
  • Compile mode — anchor memory to source code. Authored notes decay over time; compiled notes are grounded in a symbol's content hash and recompile when the code changes, not when they age. Both live in one store on a continuum.
  • Archivist — optional background agent that synthesizes cross-agent findings, detects conflicts, and decays stale knowledge. Frequently-read entries are heat-protected and skipped during decay.

Mesh

Each instance publishes memory as Atom and JSON Feed. Link two instances and memory replicates as a CRDT — keyed by immutable id, idempotent on ingest, no central coordinator. LAN peers discover each other via mDNS (_artel._tcp.local.) and link with one click. Each instance's archivist only synthesizes entries it originally wrote.

Convergence guarantees
  • Stable identity. Propagated entries keep their origin UUID — never re-minted on ingest.
  • No loops. Re-receiving a known id is a no-op. Entries tagged with your own instance's origin are skipped. A → B → A terminates; A → B → C propagates.
  • Convergence. Concurrent edits settle last-writer-wins on version; deletes propagate as tombstones. The topology can contain cycles safely.

Pinned by tests in tests/test_feeds.py.


Compile mode

Mesh is one half of the symmetry: many agents converging on one shared truth. Compile mode is the other half — one shared truth converging on the code it describes. Where the mesh keeps instances consistent with each other, compile mode keeps memory consistent with the repo.

Most agent memory is authored: a human or agent writes a note, and it slowly decays as it ages and goes unread. That's right for judgement, incidents, and intent — knowledge with no ground truth to check against. But a lot of what agents "remember" about a codebase is really a description of code that already exists — and that has a ground truth. Compiled memory is anchored to it.

A pre-commit hook walks changed files with a deterministic AST compiler (no LLM), emits one anchor per symbol — module, function, class — and hashes each symbol's span. Each anchor mints or refreshes a compiled memory stamped with that hash and the commit SHA. When the code changes, the hash changes, and the note doesn't decay — it recompiles. Memory that's wrong about the code is rebuilt, not slowly forgotten.

Authored and compiled are endpoints of a continuum, not two modes. They share one store, one search index, one API. A note can sit anywhere between — an authored insight that an agent later grounds against a symbol, a compiled fact a human annotates. The same GET /memory/search returns both.

The knowledge graph is what makes the continuum real. Memories and code anchors are nodes of one heterogeneous graph; edges are typed:

  • grounds — an anchor grounds a memory in real code
  • relies_on — one node's meaning depends on another's (the dependency graph of meaning)
  • applies_to — an authored note applies to a region of code
  • corroborates / contradicts — agreement and tension between notes

Invalidation propagates backward along relies_on, exactly like gcc -MMD incremental builds: change g, and every compiled note that relies on g is marked stale, transitively. The module anchor hashes the file's shape (its sorted imports and top-level symbols), not its bytes, so editing one function body doesn't restale the whole module.

Viability is connectivity — derived, never stored. There's no "groundedness" score. An ungrounded memory is just a bare node on the graph, and a bare node is forgettable. The more a memory is connected — fresh groundings, corroborations, things that rely on it — the more viable it is; contradictions and stale groundings pull it down:

raw   = fresh_grounds + 0.5·backlinks + 0.3·corroborates − contradictions − 0.5·stale_grounds
score = 0           if raw ≤ 0
        1 − 2^(−raw) otherwise

So a fresh, grounded note that nothing disputes scores well; the moment something contradicts it the score collapses toward zero. The computation is live — GET /graph/:id recomputes it from the current edges every time, so nothing can go stale behind your back.

Why you can trust it. A compiled note carries the source SHA it was built from. Freshness is a hash comparison, not a judgement call: POST /compile/check answers fresh / stale / unknown per symbol. Fresh means the code hasn't moved since the note was built — you can act on the note without re-reading the code. That's the whole point: trustworthy enough to not check.

Setup is one line — or just ask. Tell any connected agent "set up compile mode" and it calls the compile_setup MCP tool, which hands back the installer. Or run it yourself from the repo root:

# installs a pre-commit hook: a single self-contained, stdlib-only Python file.
# no `pip install` in your repo, and it's a safe no-op until creds are set.
curl -fsSL "$ARTEL/compile/install.sh" | sh
export ARTEL_AGENT_ID=myagent ARTEL_AGENT_KEY=… ARTEL_PROJECT=myrepo

# seed the whole repo once; later commits compile only what changed
python3 "$(git rev-parse --show-toplevel)/.git/hooks/artel_compile.py" --all

# inspect compile health and the graph
curl "$ARTEL/compile/stale?project=myrepo"        # notes whose code moved out from under them
curl "$ARTEL/graph/$NODE_ID"                       # node, edges, live viability

Every property above — SHA freshness, relies_on invalidation, module-shape stability across body edits, viability collapsing on contradiction, compiled memory never decaying or merging — is pinned by tests/test_compile.py. The compiler is deterministic and LLM-free, so the tests are exact, not probabilistic.


Archivist

Optional background process — the server works without it.

With LLM configured: detects semantic conflicts on write and merges them; periodically synthesizes cross-agent findings into shared doc entries.

Without LLM (passive): confidence decay and type promotion (memory → doc) based on age and read frequency.

Adaptive decay: every GET /memory/:id read increments a heat counter. Before decaying an entry the archivist computes heat = read_count × 0.9^(weeks_since_last_read) — entries above the threshold are skipped. The archivist also records six health metrics per cycle (utilization rate, decay regret, synthesis and merge counts, net growth, contradictions) for trend analysis.

Supports Anthropic and any OpenAI-compatible provider.


Dashboard

Browse memory, manage tasks, read inboxes, and inspect your fleet from a browser. Access at http://<host>:8000/ui.

Dashboard

Tasks tab

Messages tab

Agents tab

Sessions tab


Memory

import httpx

agent = httpx.Client(
    base_url="http://<host>:8000",
    headers={"x-agent-id": "my-agent", "x-api-key": "my-key"},
)

agent.post("/memory", json={
    "content": "orders-service p99 spiked at 03:14 UTC. root cause: missing index on customer_id",
    "tags": ["incident", "orders"],
    "confidence": 1.0,
})

results = agent.get("/memory/search", params={"q": "orders latency root cause"}).json()

Entries carry confidence scores (0.0–1.0) that decay if not reinforced. Provenance tracks which agent wrote each entry and from which parents. Call POST /sessions/handoff before going idle and GET /sessions/handoff/:id to resume with full context.


Claude Code (MCP)

The onboard script writes .mcp.json automatically. Manual config:

{
  "mcpServers": {
    "artel": {
      "type": "http",
      "url": "http://<host>:8000/mcp",
      "headers": {
        "x-agent-id": "<agent-id>",
        "x-api-key": "<api-key>"
      }
    }
  }
}

Artel also supports OAuth 2.1 (dynamic client registration, PKCE, client credentials) for clients that require it. See /mcp for the live tool list.

One-click install

Add to Cursor
Install in VS Code

Claude Code plugin

/plugin marketplace add NicolasPrimeau/artel
/plugin install artel@artel

REST API

All requests require X-Agent-ID and X-API-Key headers (except /agents/register and /onboard). Full schema: openapi.json.

Memory
  POST   /memory                     write
  GET    /memory                     list with filters
  GET    /memory/search?q=           semantic search
  GET    /memory/delta?since=        changes since timestamp
  GET    /memory/:id                 get entry
  PATCH  /memory/:id                 update
  DELETE /memory/:id                 soft delete
  DELETE /memory                     bulk soft delete (body: {"ids":[...]})
  GET    /memory/feed.atom           Atom 1.0 feed
  GET    /memory/feed.json           JSON Feed 1.1 (mesh substrate)

Tasks
  POST   /tasks                      create
  GET    /tasks                      list
  GET    /tasks/:id                  get task
  PATCH  /tasks/:id                  update
  POST   /tasks/:id/claim            claim
  POST   /tasks/:id/unclaim          unclaim
  POST   /tasks/:id/complete         complete
  POST   /tasks/:id/fail             fail
  GET    /tasks/:id/comments         list comments
  POST   /tasks/:id/comments         add comment

Messages
  POST   /messages                   send
  GET    /messages                   list all sent/received (?read=true|false&limit=)
  GET    /messages/inbox             unread inbox
  POST   /messages/inbox/read-all    mark all read
  GET    /messages/:id               get message by ID
  POST   /messages/:id/read          mark one read

Projects
  POST   /projects                   create and join
  GET    /projects                   list
  GET    /projects/mine              your projects
  POST   /projects/:id/join          join
  DELETE /projects/:id/leave         leave

Feeds
  GET    /feeds                      list subscriptions
  POST   /feeds                      subscribe
  PATCH  /feeds/:id                  update name/tags/interval
  DELETE /feeds/:id                  unsubscribe

Mesh
  GET    /mesh/peers                 list linked peers
  POST   /mesh/peers                 link a peer
  DELETE /mesh/peers/:id             unlink
  POST   /mesh/peers/:id/sync        sync now
  GET    /mesh/discovered            LAN peers via mDNS
  POST   /mesh/link-discovered       link a discovered peer
  POST   /mesh/handshake             mutual handshake (unauthenticated, RFC 1918 only)
  GET    /mesh/tokens                list mesh tokens
  POST   /mesh/tokens                create token
  PATCH  /mesh/tokens/:id            update token
  DELETE /mesh/tokens/:id            revoke token

Agents
  POST   /agents/register            register
  PATCH  /agents/me                  rename self
  PATCH  /agents/:id                 rename any (owner)
  DELETE /agents/:id                 delete (owner)
  GET    /agents                     list with presence (api_key shown to owner only)
  GET    /onboard                    onboarding script

Logs
  POST   /logs                       write log entry (agent+)
  GET    /logs                       list entries (owner)

OAuth (for MCP clients that require it)
  GET    /.well-known/oauth-authorization-server
  POST   /oauth/register             dynamic client registration
  GET    /oauth/authorize            authorization code + PKCE
  POST   /oauth/token                token endpoint

Other
  POST   /events                    emit event
  GET    /events/stream             SSE stream
  POST   /sessions/handoff          save handoff
  GET    /sessions/handoff          load handoff + memory delta (your own)

Configuration

Variable Default Description
AGENT_KEYS agent-id:api-key pairs, comma-separated. Optional :proj1;proj2 suffix scopes an agent to projects.
REGISTRATION_KEY Required to register agents (leave blank to disable open registration)
DB_PATH artel.db SQLite path
PUBLIC_URL Base URL for onboard script and OAuth metadata
UI_PASSWORD Web UI password
UI_AGENT_ID artel-ui Dashboard agent, auto-created on startup
UI_DEFAULT_THEME gruvbox Default UI theme for new sessions. Options: gruvbox, tokyo-night, nord, dracula, kanagawa, rose-pine, everforest, monokai, cobalt, solarized, hacker, mellow, volcano, ayu, flexoki, oxocarbon
ARCHIVIST_PROVIDER anthropic LLM provider: anthropic or openai
ARCHIVIST_MODEL Defaults to claude-sonnet-4-6 / gpt-4o
ARCHIVIST_API_KEY Falls back to ANTHROPIC_API_KEY for Anthropic
ARCHIVIST_BASE_URL OpenAI-compatible base URL (Ollama, Mistral, etc.)
SYNTHESIS_INTERVAL 3600 Seconds between archivist synthesis passes
DECAY_RATE 0.9 Confidence multiplier per decay cycle
DECAY_WINDOW_DAYS 7 Days before decay applies to unmodified entries

Development

uv sync --dev
uv run pytest tests/ -v

License

MIT. See LICENSE.md.

Yorumlar (0)

Sonuc bulunamadi