Skip to content

Repository files navigation

⚡ Aligner

Visual feedback loop for AI agents. You describe what you want, the AI generates a diagram, you edit it visually, and the AI sees your changes.

Inspired by CJ Hess's Flowy concept

The Loop

┌─────────────────┐         ┌─────────────────┐         ┌─────────────────┐
│   AI Agent      │────────▶│ ~/.aligner/     │────────▶│   Browser UI    │
│  generates JSON │         │  global/*.json  │         │  renders flow   │
└─────────────────┘         └─────────────────┘         └─────────────────┘
         ▲                                                       │
         │                                                       │
         │                  ┌─────────────────┐                  │
         └──────────────────│   You edit &    │◀─────────────────┘
                            │   comment       │
                            └─────────────────┘

Quick Start

# Clone
git clone https://github.com/carmandale/aligner.git
cd aligner

# Install dependencies
npm install
cd server && npm install && cd ..

# Start API server + viewer (single command)
npm start
# or: ./bin/aligner start
# This also installs the "aligner" command if a writable PATH dir is available.

# Open browser
open http://127.0.0.1:5173

Initialize for your project

# In a git repo: creates .aligner/ at repo root, registers, updates .gitignore
aligner init

# Not in a git repo: creates a chart in ~/.aligner/global/
aligner init

# Also create a chart during init
aligner init --chart "architecture-overview"

# Force global chart even inside a repo
aligner init --global --name "cross-project-map"

Configuration

Aligner defaults to 127.0.0.1 (not localhost) to avoid IPv6 ambiguity.

Ports (Dynamic)

Ports are assigned dynamically - Aligner finds available ports starting from:

  • Server: 3001 (increments if in use)
  • Viewer: 5173 (increments if in use)

This allows multiple Aligner instances (or other projects) to run simultaneously without conflicts.

Server state is tracked in ~/.aligner/state/ so aligner start can detect if already running and return the correct URLs.

Frontend API/WS URLs

The viewer reads these Vite env vars (set automatically by aligner start):

  • VITE_ALIGNER_API_URL - API endpoint
  • VITE_ALIGNER_WS_URL - WebSocket endpoint

Features

  • Interactive canvas - Drag nodes, create connections, delete with backspace
  • Threaded comments - Click a node, add comments, AI can reply
  • Real-time sync - Visual edits save to JSON automatically
  • AI-readable - Simple JSON format any LLM can generate and parse
  • Multi-repo support - Manage diagrams across multiple repositories from one UI
  • Shareable links - URL reflects current chart for easy sharing between agents

Sharing Charts

Each chart has a unique shareable URL. When viewing "groovetech-profile-media-flow.json", the URL becomes:

http://127.0.0.1:5173/?chart=global::groovetech-profile-media-flow.json

Share with other agents:

  1. Click the Share button in the diagram info panel (top-left of canvas)
  2. The URL is copied to clipboard
  3. Paste the URL to another agent - they'll open directly to that chart

URL format: ?chart=<repoPath>::<filename>

  • Global diagrams: ?chart=global::my-diagram.json
  • Repo diagrams: ?chart=/path/to/repo::my-diagram.json

Multi-Repo Support

Aligner can manage diagrams across multiple repositories from a single UI. Each repo gets its own .aligner/ directory, and diagrams are grouped by repository in the UI.

Note: The commands below assume aligner is on your PATH. Running npm start once will install it; otherwise use ./bin/aligner.

Setup

# In each repo you want to track:
cd /path/to/my-repo
aligner init --name "My Repo"   # creates .aligner/ + registers it (idempotent)

# If .aligner/ already exists:
aligner register --name "My Repo"

# Inspect registry
aligner repos

# List diagrams across all repos + global
aligner list

# Remove a repo from tracking (does not delete .aligner/)
aligner unregister

Moving Charts Between Global and Repo

# Move a global chart into the current repo
aligner adopt scratch

# Move with a different name (resolve conflicts)
aligner adopt scratch --rename scratch-v2

# Move a repo chart back to global
aligner eject architecture-overview

How It Works

  • Context-aware init: Detects git repo and adjusts behavior automatically
  • Registry: ~/.aligner/registry.json tracks all registered repos
  • Global diagrams: Stored in ~/.aligner/global/
  • Repo diagrams: Each repo stores diagrams in .aligner/ (auto-added to .gitignore)
  • File watcher: Monitors all registered repos for diagram changes
  • WebSocket: Real-time updates push changes to all connected browsers
  • UI grouping: Diagrams grouped by repository with collapsible sections

Note on older diagram locations

If you have older diagrams directly under ~/.aligner/ (for example ~/.aligner/foo.json), the server will move them into ~/.aligner/global/ on startup.

JSON Schema

Diagrams are stored as JSON files in either ~/.aligner/global/ or a repo's .aligner/ directory:

{
  "version": "1.0",
  "name": "My Diagram",
  "type": "flowchart",
  "nodes": [
    {
      "id": "node-1",
      "type": "rect",
      "label": "Start Here",
      "position": { "x": 100, "y": 100 },
      "size": { "width": 150, "height": 50 },
      "style": {
        "fill": "#dbeafe",
        "stroke": "#3b82f6",
        "cornerRadius": 8
      },
      "comments": [
        { "from": "user", "text": "Should this be the entry point?" },
        { "from": "agent", "text": "Yes, all flows start here." }
      ]
    }
  ],
  "edges": [
    {
      "id": "edge-1",
      "from": "node-1",
      "to": "node-2",
      "type": "arrow",
      "label": "next step"
    }
  ],
  "metadata": {
    "description": "What this diagram represents",
    "created": "2024-01-01T00:00:00.000Z",
    "modified": "2024-01-01T00:00:00.000Z"
  }
}

Node Properties

Property Type Description
id string Unique identifier
type string rect, circle, diamond
label string Text displayed (supports \n for newlines)
position object { x: number, y: number }
size object { width: number, height: number }
style.fill string Background color (hex)
style.stroke string Border color (hex)
style.cornerRadius number Border radius in pixels
comments array Thread of `{ from: "user"

Edge Properties

Property Type Description
id string Unique identifier
from string Source node ID
to string Target node ID
type string arrow, dashed, line
label string Text on the edge (optional)

Using with AI Agents

Reading Comments

# Check for user feedback
cat ~/.aligner/global/my-diagram.json | jq '.nodes[] | select(.comments) | {label, comments}'

Generating a Diagram

Prompt your AI:

Create an Aligner diagram showing a user login flow.
Save it to ~/.aligner/global/login-flow.json

Use this format:
- nodes: array with id, type, label, position, size, style
- edges: array with id, from, to, type
- Node types: rect, circle, diamond
- Edge types: arrow, dashed

Replying to Comments

When you read a user comment, add your reply to the comments array:

{
  "comments": [
    { "from": "user", "text": "Is this correct?" },
    { "from": "agent", "text": "Yes, I verified this matches the codebase." }
  ]
}

CLI Commands

From this repo, run:

  • ./bin/aligner <command> (recommended for development)
  • npm start (equivalent to ./bin/aligner start)

Running npm start (or ./bin/aligner start) installs the aligner command into the first writable directory on your PATH (for example ~/.local/bin or /opt/homebrew/bin). After that, you can run aligner init --name "My Repo" in any repo.

If no writable PATH dir is available, use ./bin/aligner directly or add one to PATH and re-run.

Commands shown as aligner <cmd> below assume it is on your PATH.

Command Description
aligner start Start server + viewer (or show URL if already running)
aligner stop Stop the server for this project
aligner status Show all running Aligner servers
aligner server Start only the API server
aligner viewer Start only the web viewer
aligner open Open the viewer URL in browser
aligner init Context-aware init (repo mode or global mode)
aligner adopt <chart> Move a global chart into the current repo
aligner eject <chart> Move a repo chart to global
aligner register Register current directory (requires .aligner/)
aligner unregister Unregister current directory
aligner repos List registered repositories + status
aligner list List all diagrams (global + registered repos)
aligner help Show help

Dev workflow

If you want to run the API server and viewer separately, use two terminals:

# Terminal 1: API server
cd server
PORT=3001 node index.js

# Terminal 2: Web UI
cd ..
VITE_ALIGNER_API_URL="http://127.0.0.1:3001" \
VITE_ALIGNER_WS_URL="ws://127.0.0.1:3001" \
npm run dev -- --host 127.0.0.1 --port 5173 --strictPort

API Endpoints

The server runs on PORT (default 3001):

Method Endpoint Description
GET /diagrams List all diagrams (grouped by repo)
GET /diagram/:repo/:filename Get diagram JSON from specific repo
PUT /diagram/:repo/:filename Update diagram in specific repo
POST /diagram/:repo Create new diagram in specific repo
DELETE /diagram/:repo/:filename Delete diagram from specific repo
GET /repos List all registered repositories

Repo identifier (:repo)

For repo-aware routes, :repo is either:

  • global (uses ~/.aligner/global/)
  • a URL-encoded absolute repo path (uses <repoPath>/.aligner/)

Example:

REPO="/tmp/my-repo"
REPO_ID=$(node -e "console.log(encodeURIComponent(process.argv[1]))" "$REPO")
curl "http://127.0.0.1:3001/diagram/$REPO_ID/my-diagram.json"

WebSocket: Connect to ws://127.0.0.1:3001 for real-time diagram updates.

Project Structure

~/.aligner/                          # Aligner home
├── registry.json                    # Multi-repo registry
└── global/                          # Global diagrams
    ├── example-flow.json
    └── my-diagram.json

/path/to/my-repo/                    # Your project repo
└── .aligner/                        # Repo-specific diagrams
    └── feature-diagram.json

~/dev/aligner/                       # The app
├── bin/
│   ├── aligner                      # CLI entry point
│   ├── aligner-init.js              # Context-aware init
│   ├── aligner-adopt.js             # Move global chart into repo
│   ├── aligner-eject.js             # Move repo chart to global
│   ├── aligner-register.js          # Register command
│   ├── lib/
│   │   ├── git.js                   # Git root detection
│   │   └── gitignore.js             # .gitignore management
│   └── ...                          # Other CLI commands
├── src/
│   ├── App.tsx                      # Main React component
│   ├── components/
│   │   ├── AlignerNode.tsx          # Custom node with animations
│   │   └── CreateDiagramModal.tsx   # Create diagram modal
│   └── styles.css                   # Tailwind + custom styles
├── server/
│   ├── index.js                     # Express API server + WebSocket
│   ├── registry.js                  # Registry manager
│   └── watcher.js                   # File watcher (chokidar)
└── package.json

Tech Stack

  • Frontend: React, Vite, ReactFlow, Framer Motion, Tailwind CSS
  • Backend: Express.js, file system watcher
  • Icons: Lucide React

License

MIT

About

Visual feedback loop for AI agents - Claude writes JSON, you edit visually, changes sync back

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages