{
  "markdown": "# trip2g\n\n**Publish your Obsidian vault as a website. Self-hosted MCP memory for AI agents.**\n\nWrite in Obsidian, press Sync, your notes are live. The same self-hosted hub serves readers a website and serves agents an MCP endpoint, publishes to Telegram, and gates paid content. Under the hood it is a Markdown Operating System: every note is a file, and one note is both a web page for a human and a tool call for an agent.\n\n[![CI](https://github.com/trip2g/trip2g/actions/workflows/ci.yml/badge.svg)](https://github.com/trip2g/trip2g/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)\n[![Release](https://img.shields.io/github/v/release/trip2g/trip2g)](https://github.com/trip2g/trip2g/releases)\n[![GitHub stars](https://img.shields.io/github/stars/trip2g/trip2g?style=flat)](https://github.com/trip2g/trip2g/stargazers)\n[![Go](https://img.shields.io/badge/go-1.26-blue.svg)](https://golang.org)\n\n**Why trip2g**\n\n- **Your notes work twice.** One markdown file renders as a page for readers and answers `search` / `note_html` calls from any MCP client. No export step, no copy of your knowledge locked in a vector store you can't read.\n- **Your data stays yours.** Plain markdown, a git-cloneable vault, every edit a readable diff. No SaaS in the middle, and you can move out any time with `git clone`.\n- **One process to run.** A single Go binary on SQLite. It starts the same on a laptop, a small VM, or a container. MIT licensed.\n\n<!-- DEMO GIF placeholder: ~15 seconds, edit a note in Obsidian, press Sync, refresh the page, then ask an MCP client about the change.\n     Drop the recording at docs/assets/demo.gif and replace this comment with:\n     ![15 second demo: edit in Obsidian, sync, the page and the agent both see it](docs/assets/demo.gif) -->\n![trip2g landing](docs/assets/screenshot.webp)\n\n## Quickstart\n\n**See it work in 30 seconds.** Add the public knowledge hub to any MCP client and ask it a question. It searches all connected bases and answers with sources:\n\n```json\n{\n  \"mcpServers\": {\n    \"trip2g\": {\n      \"url\": \"https://trip2g.com/_system/mcp\"\n    }\n  }\n}\n```\n\n**Run your own hub:**\n\n```bash\ngit clone https://github.com/trip2g/trip2g && cd trip2g/quickstart\ndocker compose up\n```\n\nOpen http://localhost:8081, sign in with `owner@example.com` and code `111111`, and download the preconfigured Obsidian vault from the home page. One container, files on local disk, full-text search — no other services needed.\n\nPrefer no terminal? Get a [free cloud instance](https://simplecloud.2pub.me). All the options (single binary, Docker Compose behind TLS, fly.io) are in the [self-host guide](https://trip2g.com/en/user/selfhosted).\n\n[Docs](https://trip2g.com/en/user) · [Getting started](https://trip2g.com/en/user/getting_started) · [MCP tools](https://trip2g.com/en/user/mcp) · [Self-host](#self-host) · [Contributing](CONTRIBUTING.md)\n\n---\n\n## Everything is a note\n\n> Unix made everything a file. trip2g makes everything a note.\n\nOne global namespace, path-addressed, shared by humans and agents. A note is a markdown file: the frontmatter is its metadata, the body is its content. The same note is served as a web page (the display server) and over MCP (the agent's syscall surface), and every edit is snapshotted into `note_versions` and mirrored to git. So the history is a readable diff, not a binary blob.\n\n```\n   human A           human B           human C\n      │                 │                 │\n      ▼                 ▼                 ▼\n   agent A           agent B           agent C\n      │                 │                 │\n      ▼                 ▼                 ▼\n  ┌────────┐  MCP  ┌────────┐  MCP  ┌────────┐\n  │ hub A  │ ◄───► │ hub B  │ ◄───► │ hub C  │\n  └────────┘       └────────┘       └────────┘\n       ▲                 ▲                 ▲\n       └─── humans browse · agents query ──┘\n```\n\nThe same hub serves the human (a website with subscriptions, RSS, Telegram) and the agent (MCP). Your data stays in plain markdown you can move out any time.\n\n---\n\n## The map\n\ntrip2g borrows the operating-system vocabulary because the primitives line up. Each row is tagged by how real it is: **shipped** is running code on `main`, **branch** is running code on `feat/agent-runtime`, **planned** is a design doc.\n\n| OS concept | trip2g primitive | Status |\n|---|---|---|\n| Filesystem | one path-addressed note namespace, humans and agents share it | shipped |\n| Files | notes: markdown frontmatter (metadata) + body (content) | shipped |\n| Overlay filesystem | frontmatter patches (Jsonnet) override notes without touching the source | shipped |\n| Snapshots | `note_versions` + DB-canonical git mirror (`gitapi`) | shipped |\n| Filesystem over git | `git clone`/`pull`/`push` the vault over Smart HTTP (`/_system/git`) | shipped |\n| Syscalls | MCP tools: `search`, `note_html`, `similar`, `federated_*` | shipped |\n| Network stack | federation: fan one query out to peer hubs | shipped |\n| Virtual hosts | per-domain routing via `route`/`routes` frontmatter | shipped |\n| Scheduler | cron webhooks (`next_run_at`) + goqite worker pools | shipped |\n| Process dispatch | webhook delivery: note create/update/remove → POST | shipped |\n| IPC | notes as an event bus: one agent's write fires the next | shipped |\n| Display server | website rendering: default + Jet templates, mermaid, datachart | shipped |\n| Page cache | anonymous rendered-page cache, version-keyed | shipped |\n| Output target | publish notes to a Telegram channel, links preserved | shipped |\n| Standard input | forms in frontmatter, submissions stored per note | shipped |\n| Permissions (users) | subgraphs + subscription ACLs, admins, API keys | shipped |\n| Auth providers | email magic-link, Google/GitHub OAuth, OIDC SSO | shipped |\n| Permissions (agents) | per-webhook `read_patterns`/`write_patterns` in a scoped token | shipped |\n| Credential store | encrypted `secrets` / `federation_secrets` (AES-256-GCM) | shipped |\n| Capability ticket | HAT: signed short-TTL token, `ae=true` admin elevation | shipped |\n| Control surface | kanban board note (`layout: kanban`) | shipped (layout), branch (agent wiring) |\n| Kernel config | feature flags, validated at boot (panics on missing dep) | shipped |\n| Process executor | internal LLM run loop (`agentruntime`), tool allowlist + caps | branch |\n| Package manager | role-as-note: drop a note, `fleet` registers the agent | branch |\n| Resource limits | non-overridable token + step caps per run | branch |\n\n---\n\n## Syscalls: the MCP server\n\nBuilt into every hub. An agent never touches the database directly. It calls a small set of [tools over MCP](https://trip2g.com/en/user/mcp), and access is scoped to the caller's subscription.\n\n| Tool | Purpose |\n|------|---------|\n| `search` | Hybrid full-text + semantic search |\n| `note_html` | Read a note (or a section) by id, path, or match |\n| `similar` | Notes similar to a given note |\n| `federated_search` / `federated_similar` / `federated_note_html` | Same, fanned out to peer hubs |\n| `instructions` | Author-defined prompt for the agent |\n\nCustom tools can be defined in note frontmatter (`mcp_method:`).\n\n---\n\n## Network stack: federation\n\n```mermaid\ngraph LR\n    O[Obsidian vault] --> H[your hub]\n    T[Telegram]       --> H\n    H <-->|MCP federation| H2[peer hub]\n    H2 --> B[their bases]\n    H -->|/_system/mcp| A[agent]\n    H2 -->|/_system/mcp| A\n```\n\n[Peer hubs](https://trip2g.com/en/user/federation) with trusted people or orgs. Each hub controls access per base. One agent question reaches the union of all connected knowledge. Loops are bounded the way IP packets are: each hub enforces `max_depth` against a per-hop counter (the `X-MCP-Federation-Depth` header), and every call carries a short-expiry, HMAC-signed token.\n\nEach hub is itself a Markdown OS, so the network is a mesh between operating systems, the way the internet is a network between computers. The rows below are common shapes, not the only ones. The protocol does not assume a topology, so you can build any of them.\n\n| Topology | Setup | Result |\n|----------|-------|--------|\n| Solo | One hub, many bases | All your notes, books, courses in one query |\n| Friends | Each person runs a hub, hubs peer | Union of everyone's knowledge |\n| Company | Central hub + per-employee hubs | Tribal knowledge and docs, queryable |\n| B2B | Two star topologies, one bridge | Shared knowledge without merging systems |\n\n---\n\n## Process dispatch & scheduler: webhook agents\n\nThe kernel-side mechanism that runs an agent. Shipped on `main`.\n\n- **[Change webhooks](https://trip2g.com/en/user/webhooks).** A note create/update/remove POSTs to an agent, and the agent writes notes back via the API. Glob filtering picks which notes fire it, HMAC signs the delivery, and `max_depth` stops recursion.\n- **Cron webhooks.** Run an agent on a schedule (`0 9 * * *`). A `next_run_at` column plus a per-minute system cron drive it, and goqite worker pools give per-queue concurrency and priority. Sync or async, with optional instruction context.\n\nThe agent itself can live anywhere. These webhooks just deliver the event and accept note writes back.\n\n---\n\n## Userland: the agent fleet\n\n> *In development on `feat/agent-runtime`, not yet on `main`.*\n\nThe core idea: a note edit spawns a scoped, server-side agent run. Unlike a local editor or a static builder, the agent runs on the hub, scoped to the note's glob patterns, not on your laptop.\n\nAn agent is a note. Its frontmatter is the config: `model`, `tools`, `read_patterns`/`write_patterns`, `trigger_on`, `for_each`, `max_depth`, `timeout_seconds`. Its body is the instruction, a Jet template that can reference the changed note(s). A `fleet` daemon watches an agents folder, parses each role note, and registers it as a change webhook pointed back at itself. Drop a note to install an agent, remove the note to uninstall it.\n\n```mermaid\ngraph LR\n  E[note edited] --> W[change webhook fires]\n  W --> F[fleet /deliver]\n  F --> R[agentruntime loop]\n  R -->|search / read_note| KB[(knowledge base)]\n  R -->|write_note / patch_note| KB\n  KB -.re-trigger.-> E\n```\n\nWhen a watched note changes, trip2g fires the webhook and the fleet runs a scoped loop (`agentruntime`): the model gets the instruction plus in-scope context and calls `search` / `read_note` / `write_note` / `patch_note`. Reads and writes are enforced against the role's glob patterns, a non-overridable token-and-step cap limits the run, and `max_depth` breaks re-trigger loops. trip2g stays a plain event source. The instruction, scope, and triggers all live in the note.\n\nThe plumbing this rides on (change/cron webhooks, scoped tokens, delivery jobs) is shipped on `main`. The in-note LLM executor (`agentruntime`) and the fleet reconciler (`internal/fleet`, `cmd/fleet`) are what `feat/agent-runtime` adds.\n\n---\n\n## Control surface: the kanban board\n\nA board is a note with [`layout: kanban`](https://trip2g.com/en/user/kanban), and cards are lines like `- ship the docs @status:doing @assigned:bob`. Editing a card is a note edit, so the same trigger that drives any agent can drive a triage agent that reads the board and `patch_note`s cards in place. The note is both how a human directs work and the agent's input and output.\n\nThe kanban layout (`docs/_layouts/kanban.html`) and the standalone `kanban_template` ship on `main`. Wiring a board to the fleet is part of `feat/agent-runtime`.\n\n---\n\n## Display server: templates and renderers\n\nTwo paths, pick one per knowledge base.\n\n**A. Default template** (no code, frontmatter only). Compose pages from widgets and content blocks:\n\n```yaml\n---\nheader: \"[[Navigation]]\"\nleft_sidebar: [TOC, inlinks]\ncontent: [selfcontent, magazine]\nmagazine_include_files: \"blog/**/*.md\"\nfooter: \"[[Footer]]\"\n---\n```\n\nRendered through quicktemplate. Notes can also render as HTML, JSON, or RSS via `content_type` frontmatter.\n\n**B. [Custom Jet templates](https://trip2g.com/en/user/templates)** (full control). Drop your own `.html` files into a layouts folder and switch via `layout: path/to/template`. Templates get the markdown AST, so you can iterate sections, render specific parts, and customize down to HTML. Built on the [Jet template engine](https://github.com/CloudyKit/jet).\n\nOn top of either path sit renderer extensions that the backend loads per note, only when a note asks for them: [mermaid](https://trip2g.com/en/user/mermaid) diagrams and a [`datachart`](https://trip2g.com/en/user/chartdata) widget that turns a referenced CSV into a chart (via ECharts). A note declares what it needs, and the page ships only those scripts.\n\n---\n\n## Telegram: notes become channel posts\n\nThe same notes publish to a Telegram channel, on a schedule or instantly. trip2g keeps the links intact: a wikilink to a note that has its own post points at that post, and a note that is not posted yet falls back to its page on the website, so nothing dangles. Edit the note and re-sync, and the channel post updates itself. [Full guide →](https://trip2g.com/en/user/telegram)\n\n---\n\n## Forms: structured input\n\nA note can collect input, not just show it. Put a `form:` block in the frontmatter and trip2g renders a form on the page, accepts submissions through the GraphQL API, and stores each one against the note.\n\n```yaml\n---\ntitle: Say hello\nform:\n  fields:\n    - name: email\n      type: email\n      required: true\n    - name: message\n      type: text\n      max_length: 2000\n---\n```\n\nField types and validators live in the frontmatter, Cloudflare Turnstile guards public forms by default, and `can_submit` limits who may post. Submissions land in the admin panel and a GraphQL API, and each one emails the vault admins. Define a spec once and reuse it with `form_ref:`, or attach a form to a whole folder with frontmatter patches. In OS terms, this is the note's standard input. [Full guide →](https://trip2g.com/en/user/forms)\n\n---\n\n## Git: the vault is a repo\n\ntrip2g serves the whole knowledge base over git Smart HTTP at `/_system/git`. Clone it, pull it, and push to it like any repository. The database is canonical; the git tree is not a checkout sitting on disk, `gitapi` materializes it on demand at the moment you interact with the endpoint, and a push is applied back into the notes. So you can back up the vault with `git clone` (the full history comes down with it) and script changes with a commit instead of the API.\n\n---\n\n## Monetization\n\nGroup notes into paid products with [subgraph paywalls](https://trip2g.com/en/user/monetization), while free notes stay public. Payments go through crypto (NowPayments), Patreon, or Boosty.\n\n---\n\n## Sources\n\n| Source | Status |\n|--------|--------|\n| [Obsidian](https://trip2g.com/en/user/two_way_sync) | ready: vault stays local, two-way sync |\n| [Telegram](https://trip2g.com/en/user/telegram) | ready: channel publish + history mirror |\n| [RSS output](https://trip2g.com/en/user/rss) | ready: every base exposes feeds |\n| Notion | planned |\n| Google Drive | planned |\n| Linear, Slack archive, RSS import | planned |\n\n---\n\n## Self-host\n\n```bash\ncd quickstart && docker compose up\n```\n\ntrip2g runs as one process on SQLite, with no database server to stand up, so a hub starts the same on a laptop, a small VM, or a container. When you need high availability, add read-only replicas that scale reads horizontally while a single leader takes the writes (on the `feat/read-replica` branch).\n\n[Full guide →](https://trip2g.com/en/user/selfhosted) · MIT · runs on SQLite alone; semantic search needs an embeddings API (OpenAI or any compatible endpoint), while full-text search works offline.\n\n---\n\n## Tech stack\n\n| | |\n|---|---|\n| Backend | Go, FastHTTP, gqlgen (GraphQL) |\n| Database | SQLite + [Litestream](https://litestream.io) for streaming backup |\n| Search | bleve (full-text) + embeddings via any OpenAI-compatible API (semantic) |\n| Markdown | [Goldmark](https://github.com/yuin/goldmark): wikilinks, frontmatter |\n| Templates | quicktemplate (default) + [Jet](https://github.com/CloudyKit/jet) (custom) |\n| Charts & diagrams | mermaid, ECharts (`datachart`) |\n| Frontend | [$mol](https://mol.hyoo.ru), TypeScript |\n| Assets | S3-compatible (MinIO for dev) |\n\n---\n\n## Inspiration\n\nThe OS framing is adapted from [*Markdown as an Operating System*](https://leverageai.com.au/markdown-as-an-operating-system/) and from Unix's [*everything is a file*](https://en.wikipedia.org/wiki/Everything_is_a_file). Three lines we took to heart:\n\n- **Markdown is the universal substrate.** One file every tool and every model already reads; render the website, the feed, and the git history from it.\n- **The file is the interface between processes.** An agent writing a note fires the next agent, so coordination needs no separate queue API.\n- **Human-readable diffs are the audit log.** Every edit is a `note_version` and a commit you can read in five seconds and revert.\n\n---\n\n## License\n\nMIT\n",
  "bytes": 16917,
  "sha": "97cea49f4be8d083e5666855aa91a6be817ec971e63e9a67f28c2108d47bf12f",
  "repo_slug": "trip2g/trip2g",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_trip2g_trip2g_da4312b7/readme"
}