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
81 changes: 81 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
name: Tests

on:
push:
branches: [main]
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
python:
name: python (${{ matrix.python-version }})
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip

- name: Install with dev extras
run: |
python -m pip install --upgrade pip
python -m pip install -e ".[dev]"

- name: Run ruff
run: python -m ruff check sidecar/

- name: Run tests (with coverage on py3.11)
run: |
if [ "${{ matrix.python-version }}" = "3.11" ]; then
python -m pytest sidecar/tests/ -v --tb=short --cov --cov-report=term-missing --cov-report=xml
else
python -m pytest sidecar/tests/ -v --tb=short
fi
shell: bash

- name: Upload coverage artifact
if: matrix.python-version == '3.11'
uses: actions/upload-artifact@v4
with:
name: coverage-attune-gui
path: coverage.xml

frontend:
name: frontend (Vitest)
runs-on: ubuntu-latest
timeout-minutes: 10
defaults:
run:
working-directory: editor-frontend
steps:
- uses: actions/checkout@v4

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: "20"
cache: npm
cache-dependency-path: editor-frontend/package-lock.json

- name: Install
run: npm ci

- name: Typecheck
run: npm run typecheck

- name: Lint
run: npm run lint

- name: Vitest unit tests
run: npm run test
51 changes: 26 additions & 25 deletions .help/templates/sidecar/concept.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,43 @@
---
type: concept
name: sidecar-concept
feature: sidecar
depth: concept
generated_at: 2026-05-06T03:22:24.071907+00:00
source_hash: 9a45296c182496f7a010644896af3e7b8be6dca9a5412ea5145a2d2e9d9944ab
generated_at: 2026-05-08T06:44:22.877630+00:00
source_hash: e3ed1fa3b4aba4c7d35bf2c87e344546d5ffef087a34188fb094d356b89502f8
status: generated
---

# Sidecar

## How it works
The sidecar is a local FastAPI web server that provides a browser-based interface for attune's RAG, authoring, and help systems.

Sidecar.
## What it does

The main building blocks are:
The sidecar acts as a friendly gateway between your web browser and attune's core functionality. Instead of running command-line tools directly, you interact with a local web interface that handles complex operations like corpus management, template editing, and help generation.

- **`CommandSpec`** — core component
- **`Config`** — Resolved config snapshot. Values are post-precedence.
- **`CorpusEntry`** — core component
- **`Registry`** — In-memory snapshot of ``~/.attune/corpora.json``.
- **`EditorSession`** — In-process state for a single ``(corpus, path)`` editing tab.
The sidecar serves three main roles:

Under the hood, this feature spans 90 source
files covering:
1. **Command execution** — It maintains a registry of available commands (like corpus indexing or template generation) and runs them through a unified interface
2. **File editing** — It provides real-time editing sessions for templates and other project files, with automatic conflict detection when files change on disk
3. **Configuration management** — It resolves configuration values from environment variables, config files, and defaults, presenting a consistent view across all attune tools

- Friendly guard for the unpublished ``attune_rag.editor`` submodule.
- Filesystem helpers shared across routes.
- FastAPI app factory — wires routes, CORS, and the origin guard.
## Core components

## What connects to it
**CommandSpec** defines what operations the GUI can perform. Each command has a name, description, argument schema, and executor function. Commands are grouped by profile (developer, author, support) to show relevant operations to each user type.

**Config** provides a resolved snapshot of all configuration values. It handles the precedence chain of environment variables, config files, and built-in defaults, so other components always see consistent settings.

Other parts of the codebase interact with
sidecar through these interfaces:
**EditorSession** manages the state for editing a single file through the web interface. It tracks the original content, your draft changes, and watches for external modifications to prevent conflicts.

| Interface | Purpose | File |
|-----------|---------|------|
| `CommandSpec` | — | `sidecar/attune_gui/commands.py` |
| `Config` | Resolved config snapshot. Values are post-precedence. | `sidecar/attune_gui/config.py` |
| `CorpusEntry` | — | `sidecar/attune_gui/editor_corpora.py` |
| `Registry` | In-memory snapshot of ``~/.attune/corpora.json``. | `sidecar/attune_gui/editor_corpora.py` |
| `EditorSession` | In-process state for a single ``(corpus, path)`` editing tab. | `sidecar/attune_gui/editor_session.py` |
**Registry** maintains an in-memory view of your corpus collection from `~/.attune/corpora.json`. It knows which corpora exist, which one is currently active, and whether each corpus should warn before editing.

## Security model

The sidecar only accepts connections from localhost addresses (127.0.0.1, ::1) to prevent remote access. It generates a random authentication token on startup and stores it in a local port file, ensuring only processes on your machine can connect.

For operations that require the unpublished `attune_rag.editor` module, the sidecar provides helpful error messages rather than cryptic import failures.

## File system integration

The sidecar uses atomic writes to prevent corruption when saving files. It calculates content hashes to detect when files have changed externally, allowing the editor to prompt for conflict resolution rather than silently overwriting changes.
Loading
Loading