orchai/docs/superpowers/specs/2026-04-13-orchai-design.md
thibaud-leclere 79c1f790eb Add Orchai design spec
Desktop app (Tauri + React) that monitors Tuleap trackers and
dispatches AI agents to analyze and fix tickets automatically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 09:04:30 +02:00

14 KiB

Orchai -- Design Spec

App desktop d'equipe qui surveille des trackers Tuleap et lance des agents IA pour analyser et corriger les tickets automatiquement.

Decisions cles

  • Type : App desktop (Tauri 2 + React)
  • Stack : Rust backend (Tauri), React + TypeScript frontend, SQLite embarque
  • Utilisateurs : equipe de devs, pas de distribution large
  • Zero setup : tout embarque, pas de serveur externe

Architecture globale

+--------------------------------------------------+
|                  React Frontend                   |
|  +----------+ +----------+ +-------------------+ |
|  | Projects  | | Tickets  | |  Agent Results    | |
|  | Manager   | | Monitor  | |  (report + diff)  | |
|  +----------+ +----------+ +-------------------+ |
+--------------------------------------------------+
|              Tauri IPC (commands)                  |
+--------------------------------------------------+
|                 Rust Backend                       |
|  +-----------+ +-----------+ +----------------+   |
|  |  Project   | |  Tuleap   | |    Agent       |  |
|  |  Manager   | |  Poller   | | Orchestrator   |  |
|  +-----------+ +-----------+ +----------------+   |
|  +-----------+ +-----------+                      |
|  |  Worktree  | | Notifier  |                     |
|  |  Manager   | |           |                     |
|  +-----------+ +-----------+                      |
|  +--------------------------------------------+   |
|  |           SQLite (rusqlite)                |   |
|  +--------------------------------------------+   |
+--------------------------------------------------+

5 modules backend, 1 SPA React frontend. Communication via Tauri IPC commands et events.


Module 1 : Project Manager

Gere les projets et leurs trackers surveilles.

Modele de donnees

Project {
  id: UUID
  name: String
  path: String                 -- chemin local du repo
  cloned_from: Option<String>  -- URL d'origine si clone par l'app
  base_branch: String          -- ex: "stable", "main"
  created_at: DateTime
}

WatchedTracker {
  id: UUID
  project_id: UUID             -- FK -> Project
  tracker_id: i32              -- ID du tracker Tuleap
  tracker_label: String        -- nom affiche
  polling_interval: i32        -- en minutes, defaut 10
  agent_config: AgentConfig
  filters: Vec<FilterGroup>
}

AgentConfig {
  analyst_command: String      -- ex: "claude", "codex"
  analyst_args: Vec<String>
  developer_command: String
  developer_args: Vec<String>
}

FilterGroup {                  -- groupes combines en ET
  conditions: Vec<Filter>      -- conditions dans un groupe combinees en OU
}

Filter {
  field: String                -- ex: "status", "assigned_to", "priority"
  operator: FilterOp           -- Equals, NotEquals, In, NotIn
  value: Vec<String>           -- ex: ["Nouveau", "A traiter"]
}

Exemple : (Statut Nouveau OU Statut A traiter) ET Assigne a Team Maintenance

  • FilterGroup 1 : [status IN ("Nouveau", "A traiter")]
  • FilterGroup 2 : [assigned_to IN ("Team Maintenance")]

Commandes Tauri

  • create_project(name, path_or_url, base_branch) -- cree le projet, clone si URL
  • update_project(id, ...) / delete_project(id)
  • list_projects() / get_project(id)
  • add_tracker(project_id, tracker_id, filters, agent_config)
  • update_tracker(...) / remove_tracker(id)

Module 2 : Tuleap Poller

Interroge l'API Tuleap a intervalle regulier, applique les filtres, detecte les nouveaux tickets.

Fonctionnement

  1. Un scheduler tourne en arriere-plan (tokio::interval par tracker surveille)
  2. A chaque tick, appel API Tuleap GET /api/trackers/{id}/artifacts avec les credentials
  3. Les resultats sont filtres localement selon les FilterGroup configures (l'API Tuleap ne supporte pas nativement les combinaisons ET/OU complexes)
  4. Chaque ticket est compare a la table processed_tickets -- si absent, c'est un nouveau ticket
  5. Les nouveaux tickets sont inseres en base avec le statut Pending et ajoutes a la file d'attente

Modele de donnees

ProcessedTicket {
  id: UUID
  tracker_id: UUID              -- FK -> WatchedTracker
  artifact_id: i32              -- ID du ticket Tuleap
  artifact_title: String
  artifact_data: String         -- JSON brut du ticket
  status: TicketStatus          -- Pending, Analyzing, Developing, Done, Error
  analyst_report: Option<String>
  developer_report: Option<String>
  worktree_path: Option<String>
  branch_name: Option<String>
  detected_at: DateTime
  processed_at: Option<DateTime>
}

TuleapCredentials {
  id: UUID
  tuleap_url: String
  username: String
  password: String              -- chiffre au repos
}

Points importants

  • Credentials chiffres en SQLite (cle derivee via keyring ou secret local)
  • Le poller emet un evenement Tauri new-tickets-detected vers le frontend
  • Si l'API Tuleap est injoignable, log de l'erreur et retry au prochain tick

Commandes Tauri

  • set_tuleap_credentials(url, username, password)
  • test_tuleap_connection()
  • get_tracker_fields(tracker_id) -- recupere les champs/valeurs pour les filtres UI
  • list_processed_tickets(project_id, filters)
  • manual_poll(tracker_id)

Module 3 : Agent Orchestrator

Traite les tickets de la file d'attente sequentiellement via un pipeline a 2 agents.

Pipeline

  1. L'orchestrateur consomme la file (FIFO), un ticket a la fois
  2. Etape 1 -- Analyste : lance la commande CLI configuree avec un prompt structure contenant les infos du ticket et du contexte code
  3. Le rapport markdown de l'analyste est stocke en base
  4. Etape 2 -- Developpeur : lance la commande CLI avec le rapport de l'analyste + acces au worktree
  5. Le rapport + diff sont collectes
  6. Le ticket passe en Done, le Notifier est appele

Invocation CLI

Command::new("claude")
    .arg("--print")
    .arg("--prompt")
    .arg(analyst_prompt)
    .current_dir(&project_path)
    .stdout(Stdio::piped())
    .stderr(Stdio::piped())
    .spawn()

Prompts

Analyste :

Tu es un analyste technique. Voici un ticket Tuleap a analyser.

## Ticket
- ID: {artifact_id}
- Titre: {title}
- Description: {description}
- Priorite: {priority}
- Champs additionnels: {fields}

## Contexte
- Projet: {project_name}
- Repo: {project_path}

## Ta mission
1. Analyse le ticket et identifie les fichiers/fonctions concernes
2. Explique techniquement le probleme
3. Evalue si une correction de code est necessaire
4. Produis un rapport structure en markdown

Developpeur : recoit en plus le rapport de l'analyste et travaille dans le worktree.

Gestion des erreurs

  • Timeout configurable par agent (defaut : 10 minutes)
  • Si un agent plante ou timeout, le ticket passe en Error avec le message d'erreur
  • L'utilisateur peut relancer manuellement un ticket en erreur

Evenements Tauri

  • ticket-processing-started { ticket_id, step: "analyst"|"developer" }
  • ticket-processing-progress { ticket_id, output_chunk } -- streaming stdout
  • ticket-processing-done { ticket_id }
  • ticket-processing-error { ticket_id, error }

Commandes Tauri

  • get_queue_status() -- tickets en attente + ticket en cours
  • retry_ticket(ticket_id)
  • cancel_ticket(ticket_id)
  • get_ticket_result(ticket_id) -- rapport + diff

Module 4 : Worktree Manager

Cree et gere les git worktrees temporaires pour les agents developpeurs.

Cycle de vie

Ticket detecte -> Analyse -> Fix necessaire
  -> Worktree cree (branche locale orchai/{artifact_id}) basee sur {base_branch}
  -> Agent developpeur travaille dedans
  -> Resultat pret, worktree en attente de review
  -> User review le diff dans l'app
  -> User choisit "Appliquer le fix dans ma branche" -> selectionne sa branche locale
  -> L'app cherry-pick les commits du worktree dans la branche de l'user
  -> App propose suppression du worktree
  -> User confirme -> worktree + branche orchai/ supprimes

Le code dans le worktree n'est jamais push. La branche orchai/{artifact_id} est purement locale. C'est l'utilisateur qui push sa propre branche apres avoir applique le fix.

Stockage

/chemin/du/projet/              -- repo principal
/chemin/du/projet/.orchai/      -- dossier gere par l'app
  worktrees/
    orchai-1234/                -- worktree pour le ticket #1234
    orchai-5678/

Operations git

# Creation
git worktree add .orchai/worktrees/orchai-{artifact_id} -b orchai/{artifact_id} {base_branch}

# Application du fix dans la branche de l'user
git checkout {user_branch}
git cherry-pick {commits_from_orchai_branch}

# Nettoyage
git worktree remove .orchai/worktrees/orchai-{artifact_id}
git branch -d orchai/{artifact_id}

Modele de donnees

Worktree {
  id: UUID
  ticket_id: UUID               -- FK -> ProcessedTicket
  path: String                  -- chemin absolu du worktree
  branch_name: String           -- orchai/{artifact_id}
  status: WorktreeStatus        -- Active, Merged, Deleted
  created_at: DateTime
  merged_at: Option<DateTime>
  merged_into: Option<String>   -- branche cible
}

Commandes Tauri

  • create_worktree(ticket_id) -- appele automatiquement par l'orchestrateur
  • list_worktrees(project_id)
  • apply_fix_to_branch(worktree_id, target_branch) -- cherry-pick dans la branche de l'user
  • delete_worktree(worktree_id)
  • get_worktree_diff(worktree_id) -- diff par rapport a la branche de base
  • list_local_branches(project_id) -- pour le selecteur de branche dans l'UI

Conflits de merge

  • Si le cherry-pick echoue (conflit), l'app notifie l'utilisateur avec les fichiers en conflit
  • Le cherry-pick est annule (git cherry-pick --abort), le worktree reste en place
  • L'utilisateur peut resoudre manuellement ou demander a un agent de tenter la resolution

Module 5 : Notifier

Informe l'utilisateur quand un ticket a ete traite.

Notification systeme (OS)

  • notify-rust (Linux) / API Tauri native
  • Declenchee quand un ticket passe en Done ou Error
  • Contenu : titre du ticket + resume court
  • Clic sur la notification -> ouvre l'app sur le detail du ticket

Notification in-app

  • Centre de notifications (icone avec badge compteur)
  • Liste chronologique : nouveau ticket detecte, analyse terminee, fix propose, erreur
  • Chaque notification cliquable -> navigue vers le ticket
  • Marquage lu/non-lu

Modele de donnees

Notification {
  id: UUID
  project_id: UUID
  ticket_id: Option<UUID>       -- FK -> ProcessedTicket
  type: NotificationType        -- NewTicket, AnalysisDone, FixReady, Error
  title: String
  message: String
  read: bool
  created_at: DateTime
}

Commandes Tauri

  • list_notifications(project_id, unread_only)
  • mark_notification_read(id) / mark_all_read(project_id)

Evenement Tauri

  • new-notification { notification } -- le frontend met a jour le badge en temps reel

Frontend React

Stack

  • React + TypeScript
  • Tailwind CSS
  • @tauri-apps/api pour les IPC commands et events
  • react-diff-viewer pour l'affichage des diffs
  • react-markdown pour le rendu des rapports

Navigation

Sidebar avec la liste des projets + header avec le centre de notifications.

Vues

1. Dashboard projet

  • Resume : nom, chemin, branche de base, nombre de trackers
  • Liste des trackers surveilles avec statut (actif, derniere verification, tickets traites)
  • File d'attente en cours (ticket en traitement + en attente)
  • Acces rapide aux derniers resultats

2. Configuration tracker

  • Selection du tracker Tuleap (liste via API)
  • Constructeur de filtres visuel : ajout de conditions, groupement ET/OU
  • Configuration des agents (analyste / developpeur) : commande CLI + arguments
  • Intervalle de polling

3. Liste des tickets traites

  • Tableau : ID ticket, titre, statut, date
  • Filtrage par statut
  • Clic -> detail

4. Detail ticket

  • Infos du ticket Tuleap (titre, description, priorite, assignation)
  • Rapport analyste (markdown rendu)
  • Rapport developpeur (markdown rendu)
  • Vue diff du fix (style GitHub, cote a cote)
  • Actions : "Appliquer le fix dans ma branche" (selecteur de branche), "Relancer", "Supprimer le worktree"

5. Parametres

  • Credentials Tuleap (URL, login, password) + bouton "Tester la connexion"
  • Gestion des projets (ajouter, modifier, supprimer)

Schema SQLite

CREATE TABLE projects (
  id TEXT PRIMARY KEY,
  name TEXT NOT NULL,
  path TEXT NOT NULL,
  cloned_from TEXT,
  base_branch TEXT NOT NULL DEFAULT 'main',
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE tuleap_credentials (
  id TEXT PRIMARY KEY,
  tuleap_url TEXT NOT NULL,
  username TEXT NOT NULL,
  password_encrypted TEXT NOT NULL
);

CREATE TABLE watched_trackers (
  id TEXT PRIMARY KEY,
  project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
  tracker_id INTEGER NOT NULL,
  tracker_label TEXT NOT NULL,
  polling_interval INTEGER NOT NULL DEFAULT 10,
  agent_config_json TEXT NOT NULL,
  filters_json TEXT NOT NULL,
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE processed_tickets (
  id TEXT PRIMARY KEY,
  tracker_id TEXT NOT NULL REFERENCES watched_trackers(id) ON DELETE CASCADE,
  artifact_id INTEGER NOT NULL,
  artifact_title TEXT NOT NULL,
  artifact_data TEXT NOT NULL,
  status TEXT NOT NULL DEFAULT 'Pending',
  analyst_report TEXT,
  developer_report TEXT,
  detected_at TEXT NOT NULL DEFAULT (datetime('now')),
  processed_at TEXT
);

CREATE TABLE worktrees (
  id TEXT PRIMARY KEY,
  ticket_id TEXT NOT NULL REFERENCES processed_tickets(id),
  path TEXT NOT NULL,
  branch_name TEXT NOT NULL,
  status TEXT NOT NULL DEFAULT 'Active',
  created_at TEXT NOT NULL DEFAULT (datetime('now')),
  merged_at TEXT,
  merged_into TEXT
);

CREATE TABLE notifications (
  id TEXT PRIMARY KEY,
  project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
  ticket_id TEXT REFERENCES processed_tickets(id),
  type TEXT NOT NULL,
  title TEXT NOT NULL,
  message TEXT NOT NULL,
  read INTEGER NOT NULL DEFAULT 0,
  created_at TEXT NOT NULL DEFAULT (datetime('now'))
);