AGENTS.md

This file contains guidelines for AI coding agents working on this repository.

Project Overview

Fig is a Git server and web UI built with Rust (Actix-web). It serves Git repositories over HTTP and provides a web interface for browsing repositories.

Build/Lint/Test Commands

Essential Commands (use these via just)

# Full verification (runs all checks, tests, and hurl tests)
just verify

# Format code
just fmt

# Run the application
just run

# Run hurl acceptance tests (requires server running)
just hurl test

# Run a single hurl test file
just hurl test health.hurl

# Start/stop Docker environment
just up      # kill, docker stop, docker run, hurl test
just down    # docker stop

Direct Cargo Commands

# Check code without building
cargo check

# Run linter
cargo clippy

# Format code
cargo fmt

# Run unit tests
cargo test

# Run a specific test
cargo test <test_name>

# Build release
cargo build --release

Docker Commands

# Build Docker image
just docker build

# Run Docker container
just docker run

# Stop Docker container
just docker stop

# Build and push release
just docker release <version>

Code Style Guidelines

Imports

  • Group imports: std library first, then external crates, then local modules
  • Use use crate:: for local module imports
  • Example:
    use std::path::Path;
    
    use actix_web::{HttpRequest, get, web};
    use serde::Deserialize;
    
    use crate::{config, git};
    

Formatting

  • Run cargo fmt before committing
  • Run cargo clippy and fix all warnings
  • 4 spaces for indentation (Rust default)

Types and Naming

  • Structs/Enums: PascalCase (e.g., GitRequest, Server)
  • Functions/Variables: snake_case (e.g., get_commits, project_root)
  • Constants: SCREAMING_SNAKE_CASE (e.g., TCSS, HTMX)
  • Modules: snake_case (e.g., repo.rs, bare.rs)
  • Use descriptive names; avoid abbreviations except common ones (req, ctx)

Error Handling

  • Use Result<T, E> for fallible operations
  • Propagate errors with ? operator when appropriate
  • Log errors using log::error!() before returning HTTP error responses
  • Handle Option with if let or match rather than .unwrap() in production code

HTML/Views

  • Always use htm and t.css for creating views - do not change CSS without reason
  • Use maud for HTML templating
  • Use maud::html! macro for markup
  • Use maud::DOCTYPE for doctype declaration
  • Check for HX-Request header to determine if rendering full layout or partial content
  • Structure:
    if req.headers().get("HX-Request").is_some() {
        Ok(content)
    } else {
        Ok(super::render_layout(&content))
    }
    

Request Handlers

  • Use Actix-web macros: #[get("/path")], #[post("/path")]
  • Return impl Responder or specific types like AwResult<maud::Markup>
  • Extract path params with web::Path<Params> using a #[derive(Deserialize)] struct
  • Access config via web::Data<config::Server>

Testing

  • Always use hurl commands/recipes to run format and test
  • Hurl tests are in tests/*.hurl
  • Variables in tests/variables
  • Run just hurl test for acceptance tests
  • To run a single test: just hurl test <file.hurl>

Environment Variables

  • PORT: Server port (default: 8080)
  • LOG_LEVEL: Logging level (default: info)
  • PROJECT_ROOT: Git repositories root path (default: /srv/git)
  • DB_PATH: Path to the SQLite database file (default: fig.db)
  • API_KEY: API key for user signup endpoint (auto-generated if not set)

Git Workflow

  • Do not run git commit, git push, or destructive git operations unless explicitly asked
  • The project uses semantic-release for automated versioning

Authentication System

Fig includes a complete authentication system. See docs/git-auth.md for Git authentication details.

Flow Overview

  1. Get Ticket (requires API Key) → Returns one-time signup ticket
  2. Signup (requires ticket) → Creates account
  3. Login → Sets session cookie (UI) or returns Bearer token (API)
  4. Create Namespace → Uses session (UI) or Bearer token (API)
  5. Git Operations → Uses Basic Auth with username/password

Authentication by Endpoint Type

Endpoint TypeAuth Method
Git operations (git push)Basic Auth (username:password)
Web UI pages (/auth/*)Session cookies
API endpoints (/api/*)API Key, Basic Auth, or Bearer token
Init repo (POST /init)Basic Auth

Database Schema

The system uses libsql (SQLite) for storing:

  • users: User accounts with hashed passwords
  • namespaces: Namespace definitions with owners
  • namespace_members: Many-to-many relationship for namespace access
  • tickets: Single-use tickets for signup
  • tokens: Session tokens for API/UI authentication

Security

  • Passwords are hashed using Argon2 (memory-hard password hashing)
  • API key required for ticket generation to prevent unauthorized account creation
  • Tickets are single-use for signup only
  • Per-namespace access control
  • Sessions expire after 30 days of inactivity

Dependencies

Key crates used:

  • actix-web: Web framework
  • maud: HTML templating
  • git2: Git operations
  • xshell: Shell command execution
  • serde: Serialization
  • chrono: Date/time handling
  • libsql: SQLite database for auth data
  • argon2: Password hashing
  • base64: Base64 encoding/decoding