# trip2g [Health: Active]

**Category:** 🧠 Knowledge & Memory  
**Repository:** https://github.com/trip2g/trip2g  
**GitHub Stars:** 38  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/trip2g

## Description
Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "trip2g": {
    "command": "npx",
    "args": ["-y","trip2g"]
  }
}
```

## Documentation & README

# trip2g

**Publish your Obsidian vault as a website. Self-hosted MCP memory for AI agents.**

Write 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.

[![CI](https://github.com/trip2g/trip2g/actions/workflows/ci.yml/badge.svg)](https://github.com/trip2g/trip2g/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
[![Release](https://img.shields.io/github/v/release/trip2g/trip2g)](https://github.com/trip2g/trip2g/releases)
[![GitHub stars](https://img.shields.io/github/stars/trip2g/trip2g?style=flat)](https://github.com/trip2g/trip2g/stargazers)
[![Go](https://img.shields.io/badge/go-1.26-blue.svg)](https://golang.org)

**Why trip2g**

- **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.
- **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`.
- **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.

<!-- DEMO GIF placeholder: ~15 seconds, edit a note in Obsidian, press Sync, refresh the page, then ask an MCP client about the change.
     Drop the recording at docs/assets/demo.gif and replace this comment with:
     ![15 second demo: edit in Obsidian, sync, the page and the agent both see it](https://raw.githubusercontent.com/trip2g/trip2g/HEAD/docs/assets/demo.gif) -->
![trip2g landing](https://raw.githubusercontent.com/trip2g/trip2g/HEAD/docs/assets/screenshot.webp)

## Quickstart

**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:

```json
{
  "mcpServers": {
    "trip2g": {
      "url": "https://trip2g.com/_system/mcp"
    }
  }
}
```

**Run your own hub:**

```bash
git clone https://github.com/trip2g/trip2g && cd trip2g/quickstart
docker compose up
```

Open 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.

Prefer 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).

[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](https://github.com/trip2g/trip2g/blob/HEAD/CONTRIBUTING.md)

---

## Everything is a note

> Unix made everything a file. trip2g makes everything a note.

One 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.

```
   human A           human B           human C
      │                 │                 │
      ▼                 ▼                 ▼
   agent A           agent B           agent C
      │                 │                 │
      ▼                 ▼                 ▼
  ┌────────┐  MCP  ┌────────┐  MCP  ┌────────┐
  │ hub A  │ ◄───► │ hub B  │ ◄───► │ hub C  │
  └────────┘       └────────┘       └────────┘
       ▲                 ▲                 ▲
       └─── humans browse · agents query ──┘
```

The 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.

---

## The map

trip2g 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.

| OS concept | trip2g primitive | Status |
|---|---|---|
| Filesystem | one path-addressed note namespace, humans and agents share it | shipped |
| Files | notes: markdown frontmatter (metadata) + body (content) | shipped |
| Overlay filesystem | frontmatter patches (Jsonnet) override notes without touching the source | shipped |
| Snapshots | `note_versions` + DB-canonical git mirror (`gitapi`) | shipped |
| Filesystem over git | `git clone`/`pull`/`push` the vault over Smart HTTP (`/_system/git`) | shipped |
| Syscalls | MCP tools: `search`, `note_html`, `similar`, `federated_*` | shipped |
| Network stack | federation: fan one query out to peer hubs | shipped |
| Virtual hosts | per-domain routing via `route`/`routes` frontmatter | shipped |
| Scheduler | cron webhooks (`next_run_at`) + goqite worker pools | shipped |
| Process dispatch | webhook delivery: note create/update/remove → POST | shipped |
| IPC | notes as an event bus: one agent's write fires the next | shipped |
| Display server | website rendering: default + Jet templates, mermaid, datachart | shipped |
| Page cache | anonymous rendered-page cache, version-keyed | shipped |
| Output target | publish notes to a Telegram channel, links preserved | shipped |
| Standard input | forms in frontmatter, submissions stored per note | shipped |
| Permissions (users) | subgraphs + subscription ACLs, admins, API keys | shipped |
| Auth providers | email magic-link, Google/GitHub OAuth, OIDC SSO | shipped |
| Permissions (agents) | per-webhook `read_patterns`/`write_patterns` in a scoped token | shipped |
| Credential store | encrypted `secrets` / `federation_secrets` (AES-256-GCM) | shipped |
| Capability ticket | HAT: signed short-TTL token, `ae=true` admin elevation | shipped |
| Control surface | kanban board note (`layout: kanban`) | shipped (layout), branch (agent wiring) |
| Kernel config | feature flags, validated at boot (panics on missing dep) | shipped |
| Process executor | internal LLM run loop (`agentruntime`), tool allowlist + caps | branch |
| Package manager | role-as-note: drop a note, `fleet` registers the agent | branch |
| Resource limits | non-overridable token + step caps per run | branch |

---

## Syscalls: the MCP server

Built 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.

| Tool | Purpose |
|------|---------|
| `search` | Hybrid full-text + semantic search |
| `note_html` | Read a note (or a section) by id, path, or match |
| `similar` | Notes similar to a given note |
| `federated_search` / `federated_similar` / `federated_note_html` | Same, fanned out to peer hubs |
| `instructions` | Author-defined prompt for the agent |

Custom tools can be defined in note frontmatter (`mcp_method:`).

---

## Network stack: federation

```mermaid
graph LR
    O[Obsidian vault] --> H[your hub]
    T[Telegram]       --> H
    H <-->|MCP federation| H2[peer hub]
    H2 --> B[their bases]
    H -->|/_system/mcp| A[agent]
    H2 -->|/_system/mcp| A
```

[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.

Each 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.

| Topology | Setup | Result |
|----------|-------|--------|
| Solo | One hub, many bases | All your notes, books, courses in one query |
| Friends | Each person runs a hub, hubs peer | Union of everyone's knowledge |
| Company | Central hub + per-employee hubs | Tribal knowledge and docs, queryable |
| B2B | Two star topologies, one bridge | Shared knowledge without merging systems |

---

## Process dispatch & scheduler: webhook agents

The kernel-side mechanism that runs an agent. Shipped on `main`.

- **[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.
- **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.

The agent itself can live anywhere. These webhooks just deliver the event and accept note writes back.

---

## Userland: the agent fleet

> *In development on `feat/agent-runtime`, not yet on `main`.*

The 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.

An 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.

```mermaid
graph LR
  E[note edited] --> W[change webhook fires]
  W --> F[fleet /deliver]
  F --> R[agentruntime loop]
  R -->|search / read_note| KB[(knowledge base)]
  R -->|write_note / patch_note| KB
  KB -.re-trigger.-> E
```

When 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.

The 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.

---

## Control surface: the kanban board

A 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.

The 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`.

---

## Display server: templates and renderers

Two paths, pick one per knowledge base.

**A. Default template** (no code, frontmatter only). Compose pages from widgets and content blocks:

```yaml
---
header: "[[Navigation]]"
left_sidebar: [TOC, inlinks]
content: [selfcontent, magazine]
magazine_include_files: "blog/**/*.md"
footer: "[[Footer]]"
---
```

Rendered through quicktemplate. Notes can also render as HTML, JSON, or RSS via `content_type` frontmatter.

**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).

On 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.

---

## Telegram: notes become channel posts

The 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)

---

## Forms: structured input

A 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.

```yaml
---
title: Say hello
form:
  fields:
    - name: email
      type: email
      required: true
    - name: message
      type: text
      max_length: 2000
---
```

Field 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)

---

## Git: the vault is a repo

trip2g 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.

---

## Monetization

Group 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.

---

## Sources

| Source | Status |
|--------|--------|
| [Obsidian](https://trip2g.com/en/user/two_way_sync) | ready: vault stays local, two-way sync |
| [Telegram](https://trip2g.com/en/user/telegram) | ready: channel publish + history mirror |
| [RSS output](https://trip2g.com/en/user/rss) | ready: every base exposes feeds |
| Notion | planned |
| Google Drive | planned |
| Linear, Slack archive, RSS import | planned |

---

## Self-host

```bash
cd quickstart && docker compose up
```

trip2g 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).

[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.

---

## Tech stack

| | |
|---|---|
| Backend | Go, FastHTTP, gqlgen (GraphQL) |
| Database | SQLite + [Litestream](https://litestream.io) for streaming backup |
| Search | bleve (full-text) + embeddings via any OpenAI-compatible API (semantic) |
| Markdown | [Goldmark](https://github.com/yuin/goldmark): wikilinks, frontmatter |
| Templates | quicktemplate (default) + [Jet](https://github.com/CloudyKit/jet) (custom) |
| Charts & diagrams | mermaid, ECharts (`datachart`) |
| Frontend | [$mol](https://mol.hyoo.ru), TypeScript |
| Assets | S3-compatible (MinIO for dev) |

---

## Inspiration

The 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:

- **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.
- **The file is the interface between processes.** An agent writing a note fires the next agent, so coordination needs no separate queue API.
- **Human-readable diffs are the audit log.** Every edit is a `note_version` and a commit you can read in five seconds and revert.

---

## License

MIT

