Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 6 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The idea of [LLM-maintained knowledge bases](https://gist.github.com/karpathy/44
| The problem | The solution |
|---|---|
| Desktop apps (Tolaria, Obsidian) need Node.js, Rust, WebKit, or a display server | **Server-first**: one static binary, runs headless, `curl \| bash` to install |
| Knowledge locked in a desktop app only the local user can see | **Agents use MCP, humans use the browser** at `https://mind-map.local` |
| Knowledge locked in a desktop app only the local user can see | **Agents use MCP, humans use the browser** at `http://localhost:4242` |
| Can't deploy headless because it needs a GUI even when no human is looking | **Runs anywhere**: laptop, container, cloud VM |
| Hand-rolled search scripts that break at scale | **First-class search** powered by [SQLite FTS5](https://www.sqlite.org/fts5.html) with ranked results and snippets |
| Knowledge re-discovered via RAG on every query | **Persistent wiki** with wikilinks, backlinks, and plain `.md` files that grow over time |
Expand Down Expand Up @@ -50,8 +50,6 @@ Invoke-RestMethod https://github.com/aniongithub/mind-map/releases/latest/downlo

The installer:
- Downloads the binary and adds it to PATH
- Adds `127.0.0.1 mind-map.local` to your hosts file
- Generates a local TLS certificate so `https://mind-map.local` works with no browser warnings
- Installs mind-map as a persistent system service

Binaries available for **linux-x64**, **linux-arm64**, **darwin-x64**, **darwin-arm64**, **windows-x64**, and **windows-arm64**.
Expand All @@ -63,8 +61,8 @@ graph TD
A[Preact Web App] -->|REST API| B
C[AI Agent] -->|MCP stdio| D

subgraph "mind-map serve (HTTPS)"
B[HTTPS Server] --> E[Wiki Engine]
subgraph "mind-map serve (HTTP)"
B[HTTP Server] --> E[Wiki Engine]
end

subgraph "mind-map (stdio)"
Expand All @@ -75,14 +73,14 @@ graph TD
E -->|read/write| G[Markdown Files]
```

The web UI is a static Preact app served by `mind-map serve` over HTTPS. It uses a REST API to read and write pages. AI agents use stdio MCP, with each agent launching its own `mind-map` process.
The web UI is a static Preact app served by `mind-map serve` over HTTP. It uses a REST API to read and write pages. AI agents use stdio MCP, with each agent launching its own `mind-map` process.

## Two Modes

| Mode | Command | Use case |
|------|---------|----------|
| **stdio** (default) | `mind-map` | AI agents (Copilot, Claude, Cursor) |
| **HTTPS** | `mind-map serve` | Web UI for humans at `https://mind-map.local` |
| **HTTP** | `mind-map serve` | Web UI for humans at `http://localhost:4242` |

Both modes use the same wiki engine and the same wiki directory (`~/.mind-map/wiki` by default). Multiple stdio processes can safely share the same wiki via SQLite page locking.

Expand Down Expand Up @@ -127,7 +125,7 @@ The installer can set up mind-map as a persistent system service that starts on

```bash
# Install and start the service
sudo mind-map service install --addr 127.0.0.1:443
sudo mind-map service install --addr 127.0.0.1:4242
sudo mind-map service start

# Manage
Expand All @@ -136,23 +134,6 @@ sudo mind-map service stop
sudo mind-map service uninstall
```

## TLS Setup

The installer automatically generates a local CA and server certificate so `https://mind-map.local` works without browser warnings. You can also manage certificates manually:

```bash
# Generate certs (as your user)
mind-map tls generate

# Install CA in system trust store (requires sudo on Linux)
sudo mind-map tls install-ca --tls-dir ~/.mind-map/tls

# Remove everything
mind-map tls remove
```

On Linux, Chrome uses its own NSS certificate store. The installer handles this automatically if `libnss3-tools` is available.

## MCP Client Configuration

The installer automatically configures mind-map for GitHub Copilot, Claude, Cursor, and VS Code, and installs agent skills, so this is usually not needed. If you want to configure a client manually:
Expand Down
61 changes: 16 additions & 45 deletions cmd/mind-map/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (

"github.com/aniongithub/mind-map/internal/config"
"github.com/aniongithub/mind-map/internal/logging"
mindtls "github.com/aniongithub/mind-map/internal/tls"
"github.com/aniongithub/mind-map/internal/wiki"
mindmcp "github.com/aniongithub/mind-map/internal/mcp"
mindsync "github.com/aniongithub/mind-map/internal/sync"
Expand Down Expand Up @@ -78,7 +77,7 @@ var serveCmd = &cobra.Command{
func init() {
rootCmd.PersistentFlags().StringP("dir", "d", defaultWikiDir(), "Path to the wiki directory")

serveCmd.Flags().StringP("addr", "a", "127.0.0.1:443", "Address to listen on")
serveCmd.Flags().StringP("addr", "a", "127.0.0.1:4242", "Address to listen on")
serveCmd.Flags().String("webui", "", "Path to webui dist directory (overrides embedded webui)")
serveCmd.Flags().String("log-file", "", "Path to log file (logs to stderr and file)")
serveCmd.Flags().Duration("idle-timeout", 60*time.Second, "Idle timeout for HTTP connections (e.g. 30s, 1m)")
Expand Down Expand Up @@ -394,49 +393,21 @@ func runHTTPServer(addr, dir, webuiDir string, idleTimeout time.Duration, stopCh
IdleTimeout: idleTimeout,
}

// Serve HTTPS if TLS certs are available, otherwise HTTP.
// Derive TLS dir from the wiki dir (sibling directory) so it works
// correctly when running as a system service with a different home.
tlsDir := mindtls.DirFromWikiDir(dir)
useTLS := mindtls.HasCerts(tlsDir)

if useTLS {
certFile, keyFile := mindtls.CertPaths(tlsDir)
slog.Info("mind-map server starting",
slog.String("addr", addr),
slog.String("wiki", w.Root()),
slog.String("url", "https://"+addr),
slog.Bool("tls", true),
)

go func() {
<-stopCh
slog.Info("shutting down HTTP server")
server.Close()
}()

if err := server.ListenAndServeTLS(certFile, keyFile); err != http.ErrServerClosed {
slog.Error("server error", slog.Any("error", err))
return err
}
} else {
slog.Info("mind-map server starting",
slog.String("addr", addr),
slog.String("wiki", w.Root()),
slog.String("url", "http://"+addr),
slog.Bool("tls", false),
)

go func() {
<-stopCh
slog.Info("shutting down HTTP server")
server.Close()
}()

if err := server.ListenAndServe(); err != http.ErrServerClosed {
slog.Error("server error", slog.Any("error", err))
return err
}
slog.Info("mind-map server starting",
slog.String("addr", addr),
slog.String("wiki", w.Root()),
slog.String("url", "http://"+addr),
)

go func() {
<-stopCh
slog.Info("shutting down HTTP server")
server.Close()
}()

if err := server.ListenAndServe(); err != http.ErrServerClosed {
slog.Error("server error", slog.Any("error", err))
return err
}
slog.Info("server stopped")
return nil
Expand Down
11 changes: 3 additions & 8 deletions cmd/mind-map/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"time"

"github.com/aniongithub/mind-map/internal/logging"
mindtls "github.com/aniongithub/mind-map/internal/tls"
"github.com/kardianos/service"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -114,7 +113,7 @@ var serviceCmd = &cobra.Command{
func init() {
// Shared flags for service subcommands that need them
for _, cmd := range []*cobra.Command{serviceInstallCmd, serviceStartCmd, serviceStopCmd, serviceUninstallCmd, serviceStatusCmd} {
cmd.Flags().StringP("addr", "a", "127.0.0.1:443", "Address to listen on")
cmd.Flags().StringP("addr", "a", "127.0.0.1:4242", "Address to listen on")
cmd.Flags().StringP("dir", "d", defaultWikiDir(), "Path to the wiki directory")
cmd.Flags().String("webui", "", "Path to webui dist directory (overrides embedded)")
cmd.Flags().Duration("idle-timeout", 60*time.Second, "Idle timeout for HTTP connections (e.g. 30s, 1m)")
Expand Down Expand Up @@ -171,12 +170,8 @@ var serviceStartCmd = &cobra.Command{
return fmt.Errorf("start service: %w", err)
}
fmt.Println("Service started.")
scheme := "http"
if mindtls.HasCerts(mindtls.DirFromWikiDir(dir)) {
scheme = "https"
}
fmt.Printf(" Web UI: %s://%s\n", scheme, addr)
fmt.Printf(" MCP endpoint: %s://%s/mcp\n", scheme, addr)
fmt.Printf(" Web UI: http://%s\n", addr)
fmt.Printf(" MCP endpoint: http://%s/mcp\n", addr)
return nil
},
}
Expand Down
103 changes: 0 additions & 103 deletions cmd/mind-map/tls.go

This file was deleted.

20 changes: 2 additions & 18 deletions install.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -98,22 +98,6 @@ Remove-Item $tarballPath -Force -ErrorAction SilentlyContinue

Write-Ok "Installed to $BinaryPath"

# Add mind-map.local to hosts file for reliable local name resolution
$hostsFile = "$env:SystemRoot\System32\drivers\etc\hosts"
$hostsContent = Get-Content $hostsFile -Raw -ErrorAction SilentlyContinue
if ($hostsContent -notmatch 'mind-map\.local') {
try {
Add-Content -Path $hostsFile -Value "`n127.0.0.1 mind-map.local" -ErrorAction Stop
Write-Ok "Added mind-map.local to hosts file"
} catch {
Write-Warn "Could not update hosts file. Add '127.0.0.1 mind-map.local' manually."
}
}

# Set up TLS so https://mind-map.local works without browser warnings
Write-Step "Setting up TLS certificates..."
& $BinaryPath tls setup

# Verify
try {
& $BinaryPath --help | Out-Null
Expand Down Expand Up @@ -157,7 +141,7 @@ foreach ($dir in $SkillDirs) {
# 6. Interactive: set up as a persistent service
# ---------------------------------------------------------------------------

$DefaultPort = "443"
$DefaultPort = "4242"
$DefaultWikiDir = "$env:ProgramData\mind-map\wiki"
$servicePort = $DefaultPort

Expand Down Expand Up @@ -232,7 +216,7 @@ if ($installService -match '^[Yy]$') {
& $BinaryPath service start @svcFlags

Write-Host ""
$webUrl = if ($servicePort -eq "443") { "https://mind-map.local" } else { "https://mind-map.local:$servicePort" }
$webUrl = "http://localhost:$servicePort"
Write-Host " Web UI: $webUrl" -ForegroundColor Cyan
Write-Host ""
Write-Host " Manage with: mind-map service status|stop|start|uninstall" -ForegroundColor DarkGray
Expand Down
Loading