Amethyst

mcp
Guvenlik Denetimi
Uyari
Health Uyari
  • No license — Repository has no license file
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Community trust — 52 GitHub stars
Code Gecti
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

AMETHYST: a local-first personal operating system: one AI agent over your files, shell, tasks, calendar, notes and MCP connectors. Python + FastAPI + SQLite, React interface.

README.md

AMETHYST

A personal operating system: one AI agent over your files, shell, tasks, calendar, notes and connected services. Single-user and local-first — your data stays in a SQLite file on your machine, your secrets stay in the OS keychain, and nothing is sent anywhere except to the model provider you choose.

The AMETHYST interface


⚡ Quick Start

📖 Full guide: See QUICKSTART.md for the 2-minute setup, connecting Ollama (free local models), and API keys.

1-Line Automated Launcher (macOS / Linux / WSL2)

git clone <this repository> && cd amethyst
./run.sh
# → Opens http://127.0.0.1:8000 automatically

(On Windows Command Prompt, run run.bat. On Mac/Linux, run ./run.sh)

The script checks prerequisites, creates .venv, installs dependencies from requirements.txt, builds the web UI, initializes the local SQLite database, and opens AMETHYST in your default browser.

  • Run ./run.sh --setup (or run.bat --setup) for the interactive configuration wizard (API keys, OAuth, Cloudflare, connectors).
  • Run ./run.sh --dev for concurrent backend + frontend hot-reloading.
  • Run ./run.sh --doctor to run diagnostics.
  • See CONFIGURATION_GUIDE.md for complete setup instructions for Google Workspace, Microsoft To Do, Cloudflare Workers, and Library capture.

🐳 Run it in Docker

git clone <this repository> && cd amethyst
docker compose up
# → http://127.0.0.1:8000

One image, one process, one port: the API and the built interface come from the same origin, so there is no second service and no cross-origin request to configure. First run walks you through pointing it at a model and signing into whatever connectors you want; state lives in two volumes (./data/amethyst for the library and database, a named volume for connector tokens) and survives restarts.

Exposure warning, unhedged

AMETHYST has no authentication. Anything that can reach port 8000 can read your files, run shell commands and read your mail. The compose file publishes on 127.0.0.1 only — do not change that without putting an authenticating reverse proxy in front of it (deployment.md).

Google and Spotify sign-ins need network_mode: host (the Linux default here); the docker notes say why, and what a container degrades at honestly — desktop notifications, the shell sandbox on hardened hosts, office conversion.

Developers: CONTRIBUTING.md covers the dev install, the one-worker rule, the secrets rule and the -e rule — three traps a container image and a public repository each have one of.


What it does

Ask for something in one line. AMETHYST decides which of its tools to use, asks permission before anything that writes or runs, and shows you exactly what it did.

A multi-step turn

That turn is three tool calls — a web search, then two fetches — resolved without being nudged. The agent loop treats an empty or truncated reply as unfinished work and continues rather than ending the turn on a blank bubble.

Everything that writes or runs asks first, and the prompt names the operation, not just the tool, so approving a read-only shell command never approves a destructive one.

The permission gate


Manual Installation (pip or uv)

python3 -m venv .venv
source .venv/bin/activate               # Windows: .venv\Scripts\activate
pip install -r requirements.txt         # or: uv pip install -r requirements.txt

amethyst init                               # ~/.amethyst, the database, default config
amethyst doctor                             # what is configured and what is missing

cd frontend && npm install && npm run build
cd ..
amethyst serve --open                       # http://127.0.0.1:8000

Point it at a model. Ollama is preconfigured; a cloud provider keeps its key in the OS keychain, never in the config file:

amethyst providers catalogue               # what AMETHYST knows how to configure
amethyst providers add anthropic
amethyst secrets set amethyst/anthropic        # prompts, so the key stays out of shell history

Any OpenAI-compatible endpoint — vLLM, LM Studio, a proxy — works with no code change:

providers:
  - name: my-vllm
    base_url: http://localhost:8000/v1
    default_model: llama-3.1-8b
    context_window: 32768              # optional; otherwise it is guessed

Configure a second provider and a turn survives the first one being down: it falls back, and says which provider answered. See providers.md.


The interface, room by room

One React app over the same API the CLI uses. Every image below is a real screenshot of a running instance.

View What lives there
Chat Chat ⌘1 The transcript, the composer, the + menu — files, skills, connectors, the working directory — and inline permission prompts.
Today Today ⌘8 Calendar, task buckets, unread mail and connected tools on one page, under a briefing written each morning.
Tasks Tasks ⌘2 Task lists as a board of cards; My Day shows only what you intend to do today.
Mail Mail ⌘3 (beta) Gmail read directly — not through the connector — with a search that jumps.
Skills & connectors Skills & connectors ⌘4 Two tabs, one page: what is added and what could be. OAuth sign-ins and credentials finish here.
Automations Automations ⌘5 (beta) A prompt and an interval, run as an ordinary turn while AMETHYST is open.
Memory Memory ⌘6 Standing facts extracted after a turn, recalled in later conversations.
Library Library ⌘9 What you have read and saved — fetched, summarised, tagged and searchable.
Activity Activity ⌘7 Every tool call, with the decision that allowed it. Reached from Settings.
Status Status Providers, tools, skills and what needs attention. Reached from the degraded banner or the palette (⌘K).

Beta pages (Mail, Automations) are off until Settings → Beta pages is enabled.

Every action in the app is also in the command palette (⌘K), the + menu gathers everything the agent can be given for the next message, and ? lists every keyboard binding.

The command palette

The composer menu

Connectors

Press ? in the app for every keyboard binding; interface.md covers how each view is built and why it is this one.


What needs what — and what merely degrades

The honest table: most missing pieces cost a feature quietly rather than break a start.

this machine has then this works without it
ffmpeg + ffprobe reels and audio transcription the item is saved with a title only; says so
bubblewrap (Linux) / seatbelt (macOS) the shell sandbox commands still confirm, then run unsandboxed; amethyst doctor states which
uv/uvx and Node npx the MCP connector catalogue half the catalogue cannot start; named in each row
sqlite-vec semantic search search falls back to keyword-only, with a warning in the log
pdftotext (poppler) reading PDFs PDF extraction fails with a named error
soffice (LibreOffice) converting to .docx/.pptx the tool refuses with the install line — not in the image (~800MB); docker compose exec amethyst apt-get install -y libreoffice-writer if you need it
a provider key summaries, tags, transcription capture still works; the item says "not summarised" and enrichment can be re-run later

Connectors: zero-config, and bring-your-own

Works with nothing to register — the connector signs into your account, no app of yours needed:

  • fetch, memory, playwright, chrome-devtools — no auth at all
  • vercel — its authorization server accepts dynamic registration, so AMETHYST registers on first sign-in
  • microsoft-todo — Microsoft's own public client, device-code flow
  • github, linkedin, tavily, exa, firecrawl — an API key or an app registration of your own, pasted into the row

Needs an OAuth app registration of your own:

  • Google — and it cannot honestly be called zero-config anyway: while the app is in Testing, Google expires a test user's grant — the refresh token included — seven days after it is given, and publishing is blocked by restricted Gmail scopes (paid CASA assessment) and Branding fields that need a Search-Console-verified domain. AMETHYST's mechanism for a shared registration exists (AMETHYST_DEFAULT_GOOGLE_*), ships with no value, and would not remove the weekly renewal. The connector announces its grant age before a tool call finds out. connectors.md has the full accounting.
  • Spotify — 25 users in Development Mode, each added by email in the dashboard.

A friend contributing on their own machine never reaches yours: the shared registration, where one exists, identifies the software; every token is minted per install and stays there.


What works

Each of these was exercised end to end, not just wired up.

The agent loop. Reason → act → observe, with guards on iterations, wall-clock time, repeated calls and continuations. Streaming, retry on transient provider failures, and a stop that interrupts the loop on the server rather than just closing the browser's read.

Multi-provider runtime. One initialize-function contract per provider, a registry, and a fallback where any unrecognised provider name resolves to a generic OpenAI-compatible adapter driven by config. Provider quirks stay inside their adapter.

30 builtin tools across filesystem, shell, desktop, tasks, calendar, file conversion, document authoring, document search, the library, browser history, Reddit and X, and the open web — plus every tool any connected MCP server exposes, in the same flat namespace. The model cannot tell them apart; you can.

A permission gate with real sandboxing. Every tool declares a static risk floor the model can raise but never lower. Shell commands run under Bubblewrap on Linux and Seatbelt on macOS. Paths under ~/.ssh, ~/.aws and similar always confirm, and no stored preference can silence them.

MCP connectivity with OAuth 2.1 + PKCE, a curated catalogue, SSRF protection on URL transports, per-server circuit breaking and a one-time trust confirmation per server.

Connectors

Hybrid retrieval over a notes vault: semantic search fused with a real BM25 index (SQLite FTS5 + sqlite-vec), content-hash incremental indexing, so re-syncing an unchanged folder costs nothing.

A day you can open. Today pulls your calendar, task buckets, unread mail and connected tools onto one page, under a briefing written each morning from those same figures. In the evening a check-in is filed with the day's real numbers and no prose — the review is written from your answers, when you give them, and rolls up on the day your week ends. See journal.md.

Reels, saved by sending them. Comment @your.account on an Instagram post, or send it to the account as a message, and it lands in the library — the savetolist.com mechanic, on Meta's own API. A mention carries the permalink and the full caption; a direct message carries neither, so AMETHYST transcribes the audio through a provider you already have a key for, and the item says plainly which of the two it was. What it will not do is describe a video it has no words for. See instagram.md — and relay/README.md for the Cloudflare Worker that catches deliveries while your machine is closed.

A library of what you have read. Paste a link and AMETHYST fetches it, extracts the text to a real file under ~/.amethyst/library, and hands it to the same indexer that reads your vault — so search_documents answers from a saved article without knowing the library exists. An X/Twitter link is captured through its public oEmbed when it has no signed-in reader, a phone share through the relay lands within a poll, and everything with real text gets a summary, tags and the things it named. A paywall, a video with no transcript, or an embedding server that is not running each cost part of the capture and none of the record: the item says which. See library.md.

A brand kit that changes the output. Voice, values, palette and fonts, injected as a <brand> block into the system prompt when AMETHYST writes for you rather than to you. The Settings panel shows the literal text the model is handed, so a stored voice and an applied one cannot silently differ.

Long-term memory. Standing facts extracted by a second model call after a turn and recalled in later conversations, updated by a create/supersede diff rather than an ever-growing transcript. Switchable off, globally or per conversation.

Markdown skills, installable from any URL and browsable in a directory that reads its sources live.

The directory

Everything the agent can be given for the next message hangs off one button beside the composer — files, the working directory, skills, connectors, and the full list of tools it can currently call.

The composer menu

A web interface over the same API: streamed answers rendered as markdown, inline permission prompts, a command palette, file attachments, connector setup — catalogue, OAuth, credentials — and a keyboard layer where ? lists every binding. The side panel is context-aware: run steps on Chat, thread detail on Mail.

A CLI that does all of it: chat, serve, skills, mcp, memory, permissions, index, search, logs, capabilities, share-token, instagram, embeddings, doctor.


Three ideas carry the design

Above the dispatcher, everything is a tool. A builtin function and a JSON-RPC call to an external MCP process are indistinguishable to the model. New capability does not touch the core.

Permission is a floor the model can raise but never lower. A model's self-assessment of an opaque operation can only escalate its risk, never reduce it — which is the failure mode of trusting self-reported risk alone.

Interpretation is the model's job; computation is not. The model extracts "tomorrow"; a deterministic engine resolves it against the clock, checks the calendar, and reports conflicts back rather than guessing.


How it is put together

Interface (CLI · HTTP/SSE API · React app served by the same process)
        │
   Agent Loop ── the single owner of reason → act → observe
         ├── AI Runtime ......... provider adapters behind one contract
         ├── Tool Registry ...... one flat namespace; permission gate on every dispatch
         │     ├── builtin ...... filesystem, shell, desktop, tasks, calendar, web
         │     └── MCP .......... browser, GitHub, Google, or any server you add
         └── Retrieval .......... hybrid search over your notes
                │
        SQLite (+vec, +FTS5) · filesystem for documents · OS keychain for secrets

Two directories carry it, named for which side of the wire they are on:

backend/          the Python package — API, agent loop, runtime, tools, MCP, retrieval
  agent/          the loop, the prompt, planning and escalation
  api/main.py     every HTTP and SSE endpoint
  runtime/        provider adapters behind one contract, plus the fallback chain
  tools/builtin/  filesystem, shell, desktop, tasks, calendar, convert, documents, web
  mcp/            transports, OAuth, catalogue, lifecycle, risk
  retrieval/      chunking, embeddings, the hybrid index
  journal/        the briefing and the reviews: signals, prompts, the clock
  instagram/      the webhook, the queue and what each route actually carries
  library/        what you have read, the capture that files it, and enrichment
  media/          downloading a file and pulling its audio out, through ffmpeg
  mail/           Gmail, read directly rather than through the connector
  web/            fetching a page and reducing it to text, shared by tool and capture
  db/             schema, connection, repositories
relay/            the Cloudflare Worker that catches deliveries while you are closed
frontend/         the React app — built by Vite, served by the same process
docs/             architecture, ADRs, deployment

backend is the import name (from backend.tasks.service import TaskService); amethyst stays the command you type, the keychain service, and the name of ~/.amethyst.


What was never built

Stated plainly, because half-built features are worse than absent ones and this repository deliberately contains none:

  • A daemon. Automations, reminders and the journal wake up on their own, but only while amethyst serve is running. Nothing outlives the interface — an unattended turn that needs a permission answer at 3am has nobody to ask, so the gate denies anything outside a standing approval and records what it wanted.
  • Anything multi-user, and anything safe to publish. There is no authentication and there is not meant to be: bind it to loopback. Exactly two endpoints are built to be reached from outside — POST /api/share/capture, which is token-gated, and POST /api/instagram/webhook, whose only authentication is Meta's signature because Meta will not send a token. Reaching AMETHYST from anywhere still means a proxy in front that publishes those two paths and identity on everything else; deployment.md has the Cloudflare setup.
  • A calendar that syncs. calendar_events is a local table the agent writes; Google Calendar is reachable as MCP tools and is not mirrored into it.
  • First-party service integrations, except mail. Calendar and GitHub are reachable as MCP connectors. Gmail is the one exception: it is read directly, using the refresh token the connector already stored, because fifteen tools written to be read by a model are the wrong shape for a screen.
  • Projects, artifacts, plugins, voice input. No backing anywhere in the system.

Provider adapters for Anthropic and OpenAI were only ever run against mocks, so their wire-format translation is unverified against the real APIs. NVIDIA NIM and the OpenAI-compatible path were exercised for real.


Verifying it yourself

pytest                    # the unit suite, ~840 tests (defaults to -m 'not live')
pytest -m live            # a few more against real MCP servers (spawns processes, uses network)
ruff check backend tests

cd frontend
npm run lint && npm run build
npm run smoke             # in a real browser against a running `amethyst serve`

The smoke suite is the one that matters: it drives Chromium against a live model and asserts what a person would see. Sandbox containment is tested against the real OS and skips where unavailable.


On the look of it. The interface is deliberately an instrument panel rather than a product page: warm graphite instead of the blue-black every dark app defaults to, Space Grotesk and Archivo over IBM Plex Mono for anything the machine reports, Phosphor icons on a single grid, and colour reserved for exactly three meanings — running, waiting on you, destructive.

Built with Python 3.11+, FastAPI, SQLite, React and Vite. No licence file was ever added, so all rights are reserved by default; treat it as reference material rather than something to redistribute.

Yorumlar (0)

Sonuc bulunamadi