mobius-charles 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mobius_charles-0.3.0/PKG-INFO +178 -0
- mobius_charles-0.3.0/README.md +153 -0
- mobius_charles-0.3.0/pyproject.toml +88 -0
- mobius_charles-0.3.0/src/mobius/__init__.py +3 -0
- mobius_charles-0.3.0/src/mobius/agents/__init__.py +6 -0
- mobius_charles-0.3.0/src/mobius/agents/loader.py +175 -0
- mobius_charles-0.3.0/src/mobius/agents/personas/__init__.py +1 -0
- mobius_charles-0.3.0/src/mobius/agents/personas/architect.md +60 -0
- mobius_charles-0.3.0/src/mobius/agents/personas/contrarian.md +64 -0
- mobius_charles-0.3.0/src/mobius/agents/personas/hacker.md +60 -0
- mobius_charles-0.3.0/src/mobius/agents/personas/researcher.md +62 -0
- mobius_charles-0.3.0/src/mobius/agents/personas/simplifier.md +58 -0
- mobius_charles-0.3.0/src/mobius/agents/templates/__init__.py +1 -0
- mobius_charles-0.3.0/src/mobius/agents/templates/claude.j2.md +18 -0
- mobius_charles-0.3.0/src/mobius/agents/templates/codex.j2.md +18 -0
- mobius_charles-0.3.0/src/mobius/agents/templates/hermes.j2.md +18 -0
- mobius_charles-0.3.0/src/mobius/cli/__init__.py +416 -0
- mobius_charles-0.3.0/src/mobius/cli/command_registry.py +1181 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/__init__.py +5 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/agent.py +170 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/build.py +230 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/cancel.py +22 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/config.py +106 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/evolve.py +55 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/go.py +420 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/init.py +93 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/interview.py +781 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/lineage.py +124 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/qa.py +114 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/ralph.py +143 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/run.py +104 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/seed.py +250 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/setup.py +381 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/status.py +398 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/todo.py +162 -0
- mobius_charles-0.3.0/src/mobius/cli/commands/ultraqa.py +82 -0
- mobius_charles-0.3.0/src/mobius/cli/formatter.py +225 -0
- mobius_charles-0.3.0/src/mobius/cli/main.py +131 -0
- mobius_charles-0.3.0/src/mobius/cli/output.py +25 -0
- mobius_charles-0.3.0/src/mobius/cli/session_inspector.py +415 -0
- mobius_charles-0.3.0/src/mobius/config.py +149 -0
- mobius_charles-0.3.0/src/mobius/core/__init__.py +2 -0
- mobius_charles-0.3.0/src/mobius/core/criterion_match.py +75 -0
- mobius_charles-0.3.0/src/mobius/core/types.py +16 -0
- mobius_charles-0.3.0/src/mobius/event_schema.py +75 -0
- mobius_charles-0.3.0/src/mobius/integration/__init__.py +32 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/__init__.py +1 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/agent.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/blind-spot.md +16 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/build.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/cancel.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/evolve.md +15 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/go.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/help.md +17 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/interview.md +62 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/lineage.md +13 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/maturity.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/qa.md +13 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/ralph.md +15 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/run.md +15 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/seed.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/setup.md +19 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/status.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/todo.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/ultraqa.md +14 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/claude_commands/unstuck.md +17 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/agent/SKILL.md +18 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/blind-spot/SKILL.md +27 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/blind-spot.md +16 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/build/SKILL.md +18 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/cancel/SKILL.md +24 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/evolve/SKILL.md +24 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/evolve.md +16 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/go/SKILL.md +18 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/go.md +15 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/help/SKILL.md +48 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/interview/SKILL.md +245 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/lineage/SKILL.md +23 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/maturity/SKILL.md +18 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/qa/SKILL.md +24 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/qa.md +15 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/ralph/SKILL.md +26 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/ralph.md +16 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/run/SKILL.md +27 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/seed/SKILL.md +26 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/setup/SKILL.md +36 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/status/SKILL.md +24 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/status.md +16 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/todo/SKILL.md +18 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/ultraqa/SKILL.md +18 -0
- mobius_charles-0.3.0/src/mobius/integration/assets/skills/unstuck/SKILL.md +59 -0
- mobius_charles-0.3.0/src/mobius/logging.py +61 -0
- mobius_charles-0.3.0/src/mobius/persistence/__init__.py +5 -0
- mobius_charles-0.3.0/src/mobius/persistence/event_store.py +435 -0
- mobius_charles-0.3.0/src/mobius/persistence/projections.py +529 -0
- mobius_charles-0.3.0/src/mobius/v3a/__init__.py +22 -0
- mobius_charles-0.3.0/src/mobius/v3a/cli/__init__.py +1 -0
- mobius_charles-0.3.0/src/mobius/v3a/cli/commands.py +513 -0
- mobius_charles-0.3.0/src/mobius/v3a/cli/main.py +190 -0
- mobius_charles-0.3.0/src/mobius/v3a/matrix/__init__.py +5 -0
- mobius_charles-0.3.0/src/mobius/v3a/matrix/diff.py +88 -0
- mobius_charles-0.3.0/src/mobius/v3a/matrix/pipeline.py +122 -0
- mobius_charles-0.3.0/src/mobius/v3a/maturity/__init__.py +21 -0
- mobius_charles-0.3.0/src/mobius/v3a/maturity/scorer.py +387 -0
- mobius_charles-0.3.0/src/mobius/v3a/phase_router/__init__.py +1 -0
- mobius_charles-0.3.0/src/mobius/v3a/phase_router/handoff.py +177 -0
- mobius_charles-0.3.0/src/mobius/v3a/phase_router/resume.py +65 -0
- mobius_charles-0.3.0/src/mobius/v3a/phase_router/router.py +257 -0
- mobius_charles-0.3.0/src/mobius/v3a/phase_router/tour.py +141 -0
- mobius_charles-0.3.0/src/mobius/v3a/phase_router/transitions.py +144 -0
- mobius_charles-0.3.0/src/mobius/v3a/projections.py +163 -0
- mobius_charles-0.3.0/src/mobius/v3a/scoring/__init__.py +1 -0
- mobius_charles-0.3.0/src/mobius/v3a/scoring/engine.py +138 -0
- mobius_charles-0.3.0/src/mobius/v3a/scoring/llm_judge.py +121 -0
- mobius_charles-0.3.0/src/mobius/v3a/scoring/mechanical.py +138 -0
- mobius_charles-0.3.0/src/mobius/v3a/scoring/rationale.py +46 -0
- mobius_charles-0.3.0/src/mobius/v3a/scoring/recommend.py +77 -0
- mobius_charles-0.3.0/src/mobius/workflow/__init__.py +1 -0
- mobius_charles-0.3.0/src/mobius/workflow/_yaml.py +74 -0
- mobius_charles-0.3.0/src/mobius/workflow/ac_tree.py +329 -0
- mobius_charles-0.3.0/src/mobius/workflow/adaptive_questions.py +333 -0
- mobius_charles-0.3.0/src/mobius/workflow/blind_spot.py +1606 -0
- mobius_charles-0.3.0/src/mobius/workflow/cancel.py +206 -0
- mobius_charles-0.3.0/src/mobius/workflow/context_detector.py +605 -0
- mobius_charles-0.3.0/src/mobius/workflow/criterion_match.py +17 -0
- mobius_charles-0.3.0/src/mobius/workflow/decision.py +339 -0
- mobius_charles-0.3.0/src/mobius/workflow/doctor.py +261 -0
- mobius_charles-0.3.0/src/mobius/workflow/drift.py +96 -0
- mobius_charles-0.3.0/src/mobius/workflow/evolve.py +1034 -0
- mobius_charles-0.3.0/src/mobius/workflow/grade.py +199 -0
- mobius_charles-0.3.0/src/mobius/workflow/handoff.py +187 -0
- mobius_charles-0.3.0/src/mobius/workflow/hud.py +311 -0
- mobius_charles-0.3.0/src/mobius/workflow/ids.py +35 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview.py +192 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_contract.py +435 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_deep.py +488 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_interactive.py +170 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_memory.py +148 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_milestones.py +47 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_parsing.py +260 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_prompts.py +451 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_render.py +196 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_scoring.py +93 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_session_helpers.py +110 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_types.py +280 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/__init__.py +1 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/ambiguity_trend.py +46 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/architecte.py +32 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/avocat.py +47 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/budget_tracker.py +28 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/lemma_check.py +125 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/oracle.py +311 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/runner.py +579 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/scribe.py +126 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/socrate.py +152 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/templates/architecte-system.tmpl +1 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/templates/avocat-system.tmpl +1 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/templates/socrate-system.tmpl +1 -0
- mobius_charles-0.3.0/src/mobius/workflow/interview_v3a/transcript.py +75 -0
- mobius_charles-0.3.0/src/mobius/workflow/lateral.py +176 -0
- mobius_charles-0.3.0/src/mobius/workflow/launcher.py +210 -0
- mobius_charles-0.3.0/src/mobius/workflow/lifecycle.py +171 -0
- mobius_charles-0.3.0/src/mobius/workflow/lineage.py +201 -0
- mobius_charles-0.3.0/src/mobius/workflow/pal_router.py +284 -0
- mobius_charles-0.3.0/src/mobius/workflow/qa.py +619 -0
- mobius_charles-0.3.0/src/mobius/workflow/question_router.py +245 -0
- mobius_charles-0.3.0/src/mobius/workflow/ralph.py +580 -0
- mobius_charles-0.3.0/src/mobius/workflow/run.py +935 -0
- mobius_charles-0.3.0/src/mobius/workflow/scan.py +441 -0
- mobius_charles-0.3.0/src/mobius/workflow/seed.py +1189 -0
- mobius_charles-0.3.0/src/mobius/workflow/seed_closer.py +66 -0
- mobius_charles-0.3.0/src/mobius/workflow/session_facts.py +109 -0
- mobius_charles-0.3.0/src/mobius/workflow/templates.py +281 -0
- mobius_charles-0.3.0/src/mobius/workflow/ultraqa.py +298 -0
- mobius_charles-0.3.0/src/mobius/workflow/verify.py +244 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mobius-charles
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Local-first AI workflow CLI with event-sourced runs and deterministic agent routing.
|
|
5
|
+
Keywords: ai-agents,cli,event-sourcing,local-first,workflow
|
|
6
|
+
Author: Mobius contributors
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
15
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
16
|
+
Requires-Dist: pydantic>=2.12.0
|
|
17
|
+
Requires-Dist: rich>=14.0.0
|
|
18
|
+
Requires-Dist: typer>=0.20.0
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Project-URL: Homepage, https://github.com/charlescstpierr/mobius-charles
|
|
21
|
+
Project-URL: Repository, https://github.com/charlescstpierr/mobius-charles
|
|
22
|
+
Project-URL: Issues, https://github.com/charlescstpierr/mobius-charles/issues
|
|
23
|
+
Project-URL: Changelog, https://github.com/charlescstpierr/mobius-charles/blob/main/CHANGELOG.md
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# Mobius
|
|
27
|
+
|
|
28
|
+
[](https://github.com/charlescstpierr/mobius-charles/actions/workflows/ci.yml)
|
|
29
|
+
[](docs/benchmarks.md)
|
|
30
|
+
[](https://pypi.org/project/mobius-charles/)
|
|
31
|
+
[](LICENSE)
|
|
32
|
+
[](pyproject.toml)
|
|
33
|
+
|
|
34
|
+
Mobius est une CLI Python **local-first, auditable et déterministe** pour piloter des agents IA. Event sourcing SQLite, lineage rejouable, routage d'agent offline (PAL Router) — zéro serveur, zéro dépendance réseau. Un **chemin débutant en une commande** :
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
mobius go "je veux une app de recettes"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Cette commande clarifie l'idée, écrit `spec.yaml`, crée le seed, lance un run, puis vous indique les prochaines commandes lisibles (`mobius status`, `mobius qa`, `mobius ralph`). Quand l'exécution est activée, `go` transmet l'approbation agent au run généré par défaut; utilisez `--ask-agent` pour reprendre une validation explicite.
|
|
41
|
+
|
|
42
|
+
> **Event sourcing** — chaque décision, chaque run, chaque évaluation est un événement immuable dans SQLite (WAL). Rejouez n'importe quel état passé avec `mobius lineage`.
|
|
43
|
+
>
|
|
44
|
+
> **PAL Router** — routage déterministe offline vers l'agent optimal (claude, codex, droid) sans appel LLM. `--agent auto --approve-agent` résout localement.
|
|
45
|
+
>
|
|
46
|
+
> **Transparence totale** — le code réel reste exécuté par votre agent choisi ou vos commandes locales; Mobius orchestre le happy path et trace les preuves. Pas de serveur, pas de LLM caché.
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
Paquet public PyPI (nom de distribution: `mobius-charles`, commande installée: `mobius`) :
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv tool install mobius-charles
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
mobius --help
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Chemins équivalents :
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
pipx install mobius-charles
|
|
64
|
+
# ou depuis un checkout de développement
|
|
65
|
+
uv tool install . --force
|
|
66
|
+
./install.sh
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Puis démarrez le chemin débutant :
|
|
70
|
+
|
|
71
|
+
```sh
|
|
72
|
+
mobius go "mon idée"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Répertoire d'état
|
|
76
|
+
|
|
77
|
+
Mobius stocke l'état dans SQLite à `$MOBIUS_HOME/events.db`. Sans `MOBIUS_HOME`, le chemin par défaut est `~/.mobius/events.db`, partagé entre les projets (`shared across every Mobius project`). Pour isoler un workspace :
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
export MOBIUS_HOME="$PWD/.mobius"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`mobius init` affiche le chemin résolu et `mobius config get event_store` le retourne à tout moment.
|
|
84
|
+
|
|
85
|
+
## Démarrage rapide
|
|
86
|
+
|
|
87
|
+
```sh
|
|
88
|
+
uv tool install mobius-charles
|
|
89
|
+
mobius go "je veux une petite CLI qui salue l'utilisateur"
|
|
90
|
+
mobius status
|
|
91
|
+
mobius qa
|
|
92
|
+
mobius ralph --dry-run
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Chemin CI/script avancé :
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
export MOBIUS_HOME="$(mktemp -d)" # optionnel: isole l'état
|
|
99
|
+
cat > /tmp/mobius-fixture.yaml <<'YAML'
|
|
100
|
+
project_type: greenfield
|
|
101
|
+
goal: Livrer un petit test de fumée CLI.
|
|
102
|
+
constraints:
|
|
103
|
+
- Garder tout l'état dans le MOBIUS_HOME temporaire.
|
|
104
|
+
- Éviter les services réseau.
|
|
105
|
+
success:
|
|
106
|
+
- Interview écrit une spec.
|
|
107
|
+
- Seed crée une session.
|
|
108
|
+
- Run se termine avec succès.
|
|
109
|
+
YAML
|
|
110
|
+
mobius interview --non-interactive --input /tmp/mobius-fixture.yaml --output /tmp/mobius-spec.yaml
|
|
111
|
+
mobius seed /tmp/mobius-spec.yaml --json
|
|
112
|
+
run_id="$(mobius run --spec /tmp/mobius-spec.yaml)"
|
|
113
|
+
mobius status "$run_id" --follow
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Pour démarrer un vrai workspace :
|
|
117
|
+
|
|
118
|
+
```sh
|
|
119
|
+
mobius go "mon idée de projet"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Commandes principales
|
|
123
|
+
|
|
124
|
+
- `mobius interview` — entretien projet interactif (modes deep, quick, conversationnel) avec juge interne à 3 lentilles (Clarté, Risques, Faisabilité), breadth keeper par questions-ponts, et persistance par tour.
|
|
125
|
+
- `mobius seed` — valide une spec et crée une session seed.
|
|
126
|
+
- `mobius run` — exécute avec un agent (`--agent codex --model gpt-5.5`, `--agent claude`, `--agent droid`). Chaque run est isolé dans un git worktree pour permettre l'exécution parallèle.
|
|
127
|
+
- `mobius status` — affiche la santé globale ou le statut d'un run.
|
|
128
|
+
- `mobius qa [RUN_ID]` — évalue un run avec un juge local déterministe.
|
|
129
|
+
- `mobius evolve [RUN_ID]` — lance une boucle d'évolution depuis un run existant.
|
|
130
|
+
- `mobius cancel RUN_ID` — annule un run détaché et nettoie son PID.
|
|
131
|
+
- `mobius lineage [AGGREGATE_ID]` — affiche les ancêtres, descendants ou le hash de replay.
|
|
132
|
+
- `mobius init` — crée un `spec.yaml` de départ et initialise l'event store.
|
|
133
|
+
- `mobius setup` — installe les assets d'intégration agent.
|
|
134
|
+
- `mobius config` — affiche, lit ou modifie la configuration Mobius.
|
|
135
|
+
- `mobius handoff` — génère un prompt versionné pour un agent de code.
|
|
136
|
+
- `mobius hud` — tableau de bord basé sur les projections.
|
|
137
|
+
|
|
138
|
+
Commandes avancées :
|
|
139
|
+
|
|
140
|
+
- `mobius build` — compose une première spec guidée depuis une idée.
|
|
141
|
+
- `mobius projection` — gère le cache de projections.
|
|
142
|
+
- `mobius cold-start` — mesure le budget de démarrage à froid.
|
|
143
|
+
|
|
144
|
+
## Exécution parallèle
|
|
145
|
+
|
|
146
|
+
Chaque `mobius run` isole automatiquement l'agent dans un **git worktree** dédié. Cela permet de lancer plusieurs runs en parallèle sans conflit :
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
mobius run --spec spec-auth.yaml --agent codex --model gpt-5.5 --approve-agent
|
|
150
|
+
mobius run --spec spec-ui.yaml --agent codex --model gpt-5.5 --approve-agent
|
|
151
|
+
mobius run --spec spec-api.yaml --agent claude --model opus-4.7 --approve-agent
|
|
152
|
+
# Les 3 tournent en parallèle, chacun dans son propre espace.
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Interview Deep améliorée
|
|
156
|
+
|
|
157
|
+
Le mode `--mode deep` inclut :
|
|
158
|
+
|
|
159
|
+
- **Persistance par tour** — chaque round est sauvegardé dans un fichier JSON incrémental. Un crash ne perd aucune donnée.
|
|
160
|
+
- **Juge interne à 3 lentilles** — Clarté (Socrate), Risques (Avocat), Faisabilité (Architecte). Le juge guide silencieusement le choix des questions et hausse le ton quand un problème est détecté.
|
|
161
|
+
- **Breadth keeper** — si un axe thématique est touché 2 fois de suite, une question-pont connecte naturellement vers un axe non couvert.
|
|
162
|
+
- **Recommandations argumentées** — chaque question inclut la recommandation de Mobius avant de demander l'avis de l'utilisateur.
|
|
163
|
+
- **Reprise après crash** — détection automatique d'une interview interrompue avec 3 choix (reprendre / recommencer / voir le résumé).
|
|
164
|
+
|
|
165
|
+
## Préparation release PyPI
|
|
166
|
+
|
|
167
|
+
Avant publication, sans effet externe :
|
|
168
|
+
|
|
169
|
+
1. Vérifier que le nom PyPI public est libre/choisi : `mobius-charles` (le nom `mobius` est déjà pris sur PyPI).
|
|
170
|
+
2. Vérifier les métadonnées : `uv build --out-dir /tmp/mobius-dist`.
|
|
171
|
+
3. Valider les artefacts : `uvx twine check /tmp/mobius-dist/*`.
|
|
172
|
+
4. Installer le wheel dans un environnement propre et lancer `mobius --help`.
|
|
173
|
+
5. Tester les assets sans écrire : `mobius setup --runtime claude|codex|hermes --dry-run`.
|
|
174
|
+
6. Vérifier l'authentification de publication sans contacter PyPI : `uv run python scripts/verify_publish_auth.py`.
|
|
175
|
+
7. Publier seulement après GO explicite, idéalement via GitHub Actions `Publish PyPI` + PyPI Trusted Publishing. En local seulement si token disponible : `uv publish --token "$PYPI_TOKEN" /tmp/mobius-dist/*`.
|
|
176
|
+
8. Après publication, vérifier le paquet réellement publié : `uv run python scripts/verify_post_publish.py --version 0.3.0`.
|
|
177
|
+
|
|
178
|
+
Voir aussi [`docs/cli-reference.md`](docs/cli-reference.md), [`CHANGELOG.md`](CHANGELOG.md), [`CONTRIBUTING.md`](CONTRIBUTING.md) et [`SECURITY.md`](SECURITY.md).
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Mobius
|
|
2
|
+
|
|
3
|
+
[](https://github.com/charlescstpierr/mobius-charles/actions/workflows/ci.yml)
|
|
4
|
+
[](docs/benchmarks.md)
|
|
5
|
+
[](https://pypi.org/project/mobius-charles/)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
[](pyproject.toml)
|
|
8
|
+
|
|
9
|
+
Mobius est une CLI Python **local-first, auditable et déterministe** pour piloter des agents IA. Event sourcing SQLite, lineage rejouable, routage d'agent offline (PAL Router) — zéro serveur, zéro dépendance réseau. Un **chemin débutant en une commande** :
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
mobius go "je veux une app de recettes"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Cette commande clarifie l'idée, écrit `spec.yaml`, crée le seed, lance un run, puis vous indique les prochaines commandes lisibles (`mobius status`, `mobius qa`, `mobius ralph`). Quand l'exécution est activée, `go` transmet l'approbation agent au run généré par défaut; utilisez `--ask-agent` pour reprendre une validation explicite.
|
|
16
|
+
|
|
17
|
+
> **Event sourcing** — chaque décision, chaque run, chaque évaluation est un événement immuable dans SQLite (WAL). Rejouez n'importe quel état passé avec `mobius lineage`.
|
|
18
|
+
>
|
|
19
|
+
> **PAL Router** — routage déterministe offline vers l'agent optimal (claude, codex, droid) sans appel LLM. `--agent auto --approve-agent` résout localement.
|
|
20
|
+
>
|
|
21
|
+
> **Transparence totale** — le code réel reste exécuté par votre agent choisi ou vos commandes locales; Mobius orchestre le happy path et trace les preuves. Pas de serveur, pas de LLM caché.
|
|
22
|
+
|
|
23
|
+
## Installation
|
|
24
|
+
|
|
25
|
+
Paquet public PyPI (nom de distribution: `mobius-charles`, commande installée: `mobius`) :
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
uv tool install mobius-charles
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
mobius --help
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Chemins équivalents :
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
pipx install mobius-charles
|
|
39
|
+
# ou depuis un checkout de développement
|
|
40
|
+
uv tool install . --force
|
|
41
|
+
./install.sh
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Puis démarrez le chemin débutant :
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
mobius go "mon idée"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Répertoire d'état
|
|
51
|
+
|
|
52
|
+
Mobius stocke l'état dans SQLite à `$MOBIUS_HOME/events.db`. Sans `MOBIUS_HOME`, le chemin par défaut est `~/.mobius/events.db`, partagé entre les projets (`shared across every Mobius project`). Pour isoler un workspace :
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
export MOBIUS_HOME="$PWD/.mobius"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`mobius init` affiche le chemin résolu et `mobius config get event_store` le retourne à tout moment.
|
|
59
|
+
|
|
60
|
+
## Démarrage rapide
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
uv tool install mobius-charles
|
|
64
|
+
mobius go "je veux une petite CLI qui salue l'utilisateur"
|
|
65
|
+
mobius status
|
|
66
|
+
mobius qa
|
|
67
|
+
mobius ralph --dry-run
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Chemin CI/script avancé :
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
export MOBIUS_HOME="$(mktemp -d)" # optionnel: isole l'état
|
|
74
|
+
cat > /tmp/mobius-fixture.yaml <<'YAML'
|
|
75
|
+
project_type: greenfield
|
|
76
|
+
goal: Livrer un petit test de fumée CLI.
|
|
77
|
+
constraints:
|
|
78
|
+
- Garder tout l'état dans le MOBIUS_HOME temporaire.
|
|
79
|
+
- Éviter les services réseau.
|
|
80
|
+
success:
|
|
81
|
+
- Interview écrit une spec.
|
|
82
|
+
- Seed crée une session.
|
|
83
|
+
- Run se termine avec succès.
|
|
84
|
+
YAML
|
|
85
|
+
mobius interview --non-interactive --input /tmp/mobius-fixture.yaml --output /tmp/mobius-spec.yaml
|
|
86
|
+
mobius seed /tmp/mobius-spec.yaml --json
|
|
87
|
+
run_id="$(mobius run --spec /tmp/mobius-spec.yaml)"
|
|
88
|
+
mobius status "$run_id" --follow
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Pour démarrer un vrai workspace :
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
mobius go "mon idée de projet"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Commandes principales
|
|
98
|
+
|
|
99
|
+
- `mobius interview` — entretien projet interactif (modes deep, quick, conversationnel) avec juge interne à 3 lentilles (Clarté, Risques, Faisabilité), breadth keeper par questions-ponts, et persistance par tour.
|
|
100
|
+
- `mobius seed` — valide une spec et crée une session seed.
|
|
101
|
+
- `mobius run` — exécute avec un agent (`--agent codex --model gpt-5.5`, `--agent claude`, `--agent droid`). Chaque run est isolé dans un git worktree pour permettre l'exécution parallèle.
|
|
102
|
+
- `mobius status` — affiche la santé globale ou le statut d'un run.
|
|
103
|
+
- `mobius qa [RUN_ID]` — évalue un run avec un juge local déterministe.
|
|
104
|
+
- `mobius evolve [RUN_ID]` — lance une boucle d'évolution depuis un run existant.
|
|
105
|
+
- `mobius cancel RUN_ID` — annule un run détaché et nettoie son PID.
|
|
106
|
+
- `mobius lineage [AGGREGATE_ID]` — affiche les ancêtres, descendants ou le hash de replay.
|
|
107
|
+
- `mobius init` — crée un `spec.yaml` de départ et initialise l'event store.
|
|
108
|
+
- `mobius setup` — installe les assets d'intégration agent.
|
|
109
|
+
- `mobius config` — affiche, lit ou modifie la configuration Mobius.
|
|
110
|
+
- `mobius handoff` — génère un prompt versionné pour un agent de code.
|
|
111
|
+
- `mobius hud` — tableau de bord basé sur les projections.
|
|
112
|
+
|
|
113
|
+
Commandes avancées :
|
|
114
|
+
|
|
115
|
+
- `mobius build` — compose une première spec guidée depuis une idée.
|
|
116
|
+
- `mobius projection` — gère le cache de projections.
|
|
117
|
+
- `mobius cold-start` — mesure le budget de démarrage à froid.
|
|
118
|
+
|
|
119
|
+
## Exécution parallèle
|
|
120
|
+
|
|
121
|
+
Chaque `mobius run` isole automatiquement l'agent dans un **git worktree** dédié. Cela permet de lancer plusieurs runs en parallèle sans conflit :
|
|
122
|
+
|
|
123
|
+
```sh
|
|
124
|
+
mobius run --spec spec-auth.yaml --agent codex --model gpt-5.5 --approve-agent
|
|
125
|
+
mobius run --spec spec-ui.yaml --agent codex --model gpt-5.5 --approve-agent
|
|
126
|
+
mobius run --spec spec-api.yaml --agent claude --model opus-4.7 --approve-agent
|
|
127
|
+
# Les 3 tournent en parallèle, chacun dans son propre espace.
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Interview Deep améliorée
|
|
131
|
+
|
|
132
|
+
Le mode `--mode deep` inclut :
|
|
133
|
+
|
|
134
|
+
- **Persistance par tour** — chaque round est sauvegardé dans un fichier JSON incrémental. Un crash ne perd aucune donnée.
|
|
135
|
+
- **Juge interne à 3 lentilles** — Clarté (Socrate), Risques (Avocat), Faisabilité (Architecte). Le juge guide silencieusement le choix des questions et hausse le ton quand un problème est détecté.
|
|
136
|
+
- **Breadth keeper** — si un axe thématique est touché 2 fois de suite, une question-pont connecte naturellement vers un axe non couvert.
|
|
137
|
+
- **Recommandations argumentées** — chaque question inclut la recommandation de Mobius avant de demander l'avis de l'utilisateur.
|
|
138
|
+
- **Reprise après crash** — détection automatique d'une interview interrompue avec 3 choix (reprendre / recommencer / voir le résumé).
|
|
139
|
+
|
|
140
|
+
## Préparation release PyPI
|
|
141
|
+
|
|
142
|
+
Avant publication, sans effet externe :
|
|
143
|
+
|
|
144
|
+
1. Vérifier que le nom PyPI public est libre/choisi : `mobius-charles` (le nom `mobius` est déjà pris sur PyPI).
|
|
145
|
+
2. Vérifier les métadonnées : `uv build --out-dir /tmp/mobius-dist`.
|
|
146
|
+
3. Valider les artefacts : `uvx twine check /tmp/mobius-dist/*`.
|
|
147
|
+
4. Installer le wheel dans un environnement propre et lancer `mobius --help`.
|
|
148
|
+
5. Tester les assets sans écrire : `mobius setup --runtime claude|codex|hermes --dry-run`.
|
|
149
|
+
6. Vérifier l'authentification de publication sans contacter PyPI : `uv run python scripts/verify_publish_auth.py`.
|
|
150
|
+
7. Publier seulement après GO explicite, idéalement via GitHub Actions `Publish PyPI` + PyPI Trusted Publishing. En local seulement si token disponible : `uv publish --token "$PYPI_TOKEN" /tmp/mobius-dist/*`.
|
|
151
|
+
8. Après publication, vérifier le paquet réellement publié : `uv run python scripts/verify_post_publish.py --version 0.3.0`.
|
|
152
|
+
|
|
153
|
+
Voir aussi [`docs/cli-reference.md`](docs/cli-reference.md), [`CHANGELOG.md`](CHANGELOG.md), [`CONTRIBUTING.md`](CONTRIBUTING.md) et [`SECURITY.md`](SECURITY.md).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "mobius-charles"
|
|
3
|
+
version = "0.3.0"
|
|
4
|
+
description = "Local-first AI workflow CLI with event-sourced runs and deterministic agent routing."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
keywords = ["ai-agents", "cli", "event-sourcing", "local-first", "workflow"]
|
|
7
|
+
requires-python = ">=3.12"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
authors = [
|
|
10
|
+
{ name = "Mobius contributors" },
|
|
11
|
+
]
|
|
12
|
+
dependencies = [
|
|
13
|
+
"pydantic>=2.12.0",
|
|
14
|
+
"rich>=14.0.0",
|
|
15
|
+
"typer>=0.20.0",
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 3 - Alpha",
|
|
19
|
+
"Environment :: Console",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"License :: OSI Approved :: MIT License",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Software Development :: Build Tools",
|
|
25
|
+
"Topic :: Software Development :: Quality Assurance",
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/charlescstpierr/mobius-charles"
|
|
30
|
+
Repository = "https://github.com/charlescstpierr/mobius-charles"
|
|
31
|
+
Issues = "https://github.com/charlescstpierr/mobius-charles/issues"
|
|
32
|
+
Changelog = "https://github.com/charlescstpierr/mobius-charles/blob/main/CHANGELOG.md"
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
mobius = "mobius.cli:main"
|
|
36
|
+
|
|
37
|
+
[dependency-groups]
|
|
38
|
+
dev = [
|
|
39
|
+
"hypothesis>=6.152.4",
|
|
40
|
+
"mypy>=1.19.0",
|
|
41
|
+
"pytest>=9.0.0",
|
|
42
|
+
"pytest-cov>=7.1.0",
|
|
43
|
+
"ruff>=0.14.0",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[build-system]
|
|
47
|
+
requires = ["uv_build>=0.10.0,<0.11.0"]
|
|
48
|
+
build-backend = "uv_build"
|
|
49
|
+
|
|
50
|
+
[tool.uv.build-backend]
|
|
51
|
+
module-root = "src"
|
|
52
|
+
module-name = "mobius"
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
target-version = "py312"
|
|
56
|
+
line-length = 100
|
|
57
|
+
src = ["src"]
|
|
58
|
+
|
|
59
|
+
[tool.ruff.lint]
|
|
60
|
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
|
61
|
+
|
|
62
|
+
[tool.ruff.lint.per-file-ignores]
|
|
63
|
+
# The blind-spot catalog contains long French prose and diagram strings where
|
|
64
|
+
# wrapping would make the source harder to review without changing behavior.
|
|
65
|
+
"src/mobius/workflow/blind_spot.py" = ["E501"]
|
|
66
|
+
|
|
67
|
+
[tool.ruff.format]
|
|
68
|
+
quote-style = "double"
|
|
69
|
+
indent-style = "space"
|
|
70
|
+
|
|
71
|
+
[tool.mypy]
|
|
72
|
+
python_version = "3.12"
|
|
73
|
+
strict = true
|
|
74
|
+
files = ["src/mobius"]
|
|
75
|
+
|
|
76
|
+
[tool.pytest.ini_options]
|
|
77
|
+
addopts = "--import-mode=importlib"
|
|
78
|
+
testpaths = ["tests"]
|
|
79
|
+
|
|
80
|
+
[tool.coverage.run]
|
|
81
|
+
patch = ["subprocess"]
|
|
82
|
+
source = ["src/mobius"]
|
|
83
|
+
branch = true
|
|
84
|
+
|
|
85
|
+
[tool.coverage.report]
|
|
86
|
+
fail_under = 80
|
|
87
|
+
precision = 2
|
|
88
|
+
show_missing = true
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"""Chargeur de prompts de personas — source unique pour tous les prompts système.
|
|
2
|
+
|
|
3
|
+
Charge les fichiers .md avec une stratégie de résolution à 3 niveaux :
|
|
4
|
+
|
|
5
|
+
1. Répertoire projet-local ``.mobius/agents/`` dans le répertoire courant
|
|
6
|
+
2. Variable d'environnement ``MOBIUS_AGENTS_DIR`` — répertoire d'override utilisateur
|
|
7
|
+
3. ``importlib.resources`` — prompts embarqués dans le package
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import functools
|
|
13
|
+
import importlib.resources
|
|
14
|
+
import os
|
|
15
|
+
import re
|
|
16
|
+
from dataclasses import dataclass
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
PERSONAS = ("contrarian", "hacker", "simplifier", "researcher", "architect")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _is_safe_path(path: Path, parent: Path) -> bool:
|
|
23
|
+
"""Vérifier qu'un chemin résolu reste sous le répertoire parent (anti-symlink escape)."""
|
|
24
|
+
try:
|
|
25
|
+
resolved = path.resolve(strict=True)
|
|
26
|
+
return str(resolved).startswith(str(parent.resolve()))
|
|
27
|
+
except OSError:
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@functools.lru_cache(maxsize=32)
|
|
32
|
+
def _resolve_persona_path(name: str, _cwd: str = "") -> Path | None:
|
|
33
|
+
"""Trouver un fichier .md de persona via la stratégie d'override à 3 niveaux."""
|
|
34
|
+
filename = f"{name}.md"
|
|
35
|
+
project_dir = Path(_cwd or Path.cwd()) / ".mobius" / "agents"
|
|
36
|
+
if project_dir.is_dir():
|
|
37
|
+
path = project_dir / filename
|
|
38
|
+
if path.exists() and _is_safe_path(path, project_dir):
|
|
39
|
+
return path
|
|
40
|
+
agents_dir = os.environ.get("MOBIUS_AGENTS_DIR")
|
|
41
|
+
if agents_dir:
|
|
42
|
+
env_dir = Path(agents_dir)
|
|
43
|
+
path = env_dir / filename
|
|
44
|
+
if path.exists() and _is_safe_path(path, env_dir):
|
|
45
|
+
return path
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@functools.lru_cache(maxsize=32)
|
|
50
|
+
def load_persona(name: str) -> str:
|
|
51
|
+
"""Charger le contenu markdown complet d'une persona.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
name: Identifiant de la persona, ex. ``"contrarian"``.
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
Texte markdown complet.
|
|
58
|
+
|
|
59
|
+
Raises:
|
|
60
|
+
FileNotFoundError: Si le fichier .md est introuvable.
|
|
61
|
+
"""
|
|
62
|
+
_validate_name(name)
|
|
63
|
+
path = _resolve_persona_path(name, str(Path.cwd()))
|
|
64
|
+
if path is not None:
|
|
65
|
+
return path.read_text(encoding="utf-8")
|
|
66
|
+
|
|
67
|
+
package = importlib.resources.files("mobius.agents.personas")
|
|
68
|
+
resource = package.joinpath(f"{name}.md")
|
|
69
|
+
try:
|
|
70
|
+
return resource.read_text(encoding="utf-8")
|
|
71
|
+
except (FileNotFoundError, TypeError):
|
|
72
|
+
raise FileNotFoundError(
|
|
73
|
+
f"Persona introuvable : {name}.md "
|
|
74
|
+
f"(cherché dans MOBIUS_AGENTS_DIR et mobius.agents.personas)"
|
|
75
|
+
) from None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def load_section(name: str, section: str) -> str:
|
|
79
|
+
"""Extraire une section ``## <section>`` d'un fichier de persona."""
|
|
80
|
+
content = load_persona(name)
|
|
81
|
+
return extract_section(content, section)
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def list_personas() -> tuple[str, ...]:
|
|
85
|
+
"""Retourner les noms de toutes les personas disponibles (embarquées + projet)."""
|
|
86
|
+
names: set[str] = set(PERSONAS)
|
|
87
|
+
project_dir = Path.cwd() / ".mobius" / "agents"
|
|
88
|
+
if project_dir.is_dir():
|
|
89
|
+
for md in project_dir.glob("*.md"):
|
|
90
|
+
names.add(md.stem)
|
|
91
|
+
agents_dir = os.environ.get("MOBIUS_AGENTS_DIR")
|
|
92
|
+
if agents_dir:
|
|
93
|
+
env_path = Path(agents_dir)
|
|
94
|
+
if env_path.is_dir():
|
|
95
|
+
for md in env_path.glob("*.md"):
|
|
96
|
+
names.add(md.stem)
|
|
97
|
+
return tuple(sorted(names))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def clear_cache() -> None:
|
|
101
|
+
"""Vider le cache des prompts. Utile pour les tests."""
|
|
102
|
+
load_persona.cache_clear()
|
|
103
|
+
_resolve_persona_path.cache_clear()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def extract_section(content: str, section: str) -> str:
|
|
107
|
+
"""Extraire tout entre ``## <section>`` et le prochain ``##``."""
|
|
108
|
+
lines = content.split("\n")
|
|
109
|
+
pattern = re.compile(rf"^##\s+{re.escape(section)}\s*$", re.IGNORECASE)
|
|
110
|
+
|
|
111
|
+
start: int | None = None
|
|
112
|
+
for i, line in enumerate(lines):
|
|
113
|
+
if pattern.match(line.strip()):
|
|
114
|
+
start = i + 1
|
|
115
|
+
break
|
|
116
|
+
if start is None:
|
|
117
|
+
raise KeyError(f"Section '## {section}' introuvable")
|
|
118
|
+
|
|
119
|
+
end = len(lines)
|
|
120
|
+
for i in range(start, len(lines)):
|
|
121
|
+
if lines[i].strip().startswith("## "):
|
|
122
|
+
end = i
|
|
123
|
+
break
|
|
124
|
+
|
|
125
|
+
return "\n".join(lines[start:end]).strip()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def extract_questions(name: str) -> tuple[str, ...]:
|
|
129
|
+
"""Extraire les questions (lignes ``- item``) de la section TES QUESTIONS."""
|
|
130
|
+
section = load_section(name, "TES QUESTIONS")
|
|
131
|
+
items: list[str] = []
|
|
132
|
+
for line in section.split("\n"):
|
|
133
|
+
stripped = line.strip()
|
|
134
|
+
if stripped.startswith("- "):
|
|
135
|
+
items.append(stripped[2:].strip())
|
|
136
|
+
return tuple(items)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@dataclass(frozen=True, slots=True)
|
|
140
|
+
class PersonaData:
|
|
141
|
+
"""Données parsées d'un fichier .md de persona."""
|
|
142
|
+
|
|
143
|
+
name: str
|
|
144
|
+
philosophy: str
|
|
145
|
+
questions: tuple[str, ...]
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def load_persona_data(name: str) -> PersonaData:
|
|
149
|
+
"""Charger et parser un fichier .md de persona."""
|
|
150
|
+
content = load_persona(name)
|
|
151
|
+
|
|
152
|
+
lines = content.split("\n")
|
|
153
|
+
philosophy_lines: list[str] = []
|
|
154
|
+
past_title = False
|
|
155
|
+
for line in lines:
|
|
156
|
+
if line.startswith("# ") and not past_title:
|
|
157
|
+
past_title = True
|
|
158
|
+
continue
|
|
159
|
+
if line.startswith("## "):
|
|
160
|
+
break
|
|
161
|
+
if past_title and line.strip():
|
|
162
|
+
philosophy_lines.append(line.strip())
|
|
163
|
+
|
|
164
|
+
return PersonaData(
|
|
165
|
+
name=name,
|
|
166
|
+
philosophy=" ".join(philosophy_lines),
|
|
167
|
+
questions=extract_questions(name),
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _validate_name(name: str) -> None:
|
|
172
|
+
if name not in list_personas():
|
|
173
|
+
raise FileNotFoundError(
|
|
174
|
+
f"Persona inconnue : {name}. Personas disponibles : {', '.join(list_personas())}"
|
|
175
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Prompts de personas de pensée latérale embarqués dans le package."""
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Architect
|
|
2
|
+
|
|
3
|
+
Tu remets en question les fondations et restructures l'approche si nécessaire.
|
|
4
|
+
|
|
5
|
+
## TA PHILOSOPHIE
|
|
6
|
+
|
|
7
|
+
« Un bon architecte sait quand renforcer les fondations et quand les remplacer. Corriger un défaut structurel tôt coûte 10x moins que le corriger tard. »
|
|
8
|
+
|
|
9
|
+
Tu ne patches pas — tu restructures. Si les fondations sont bancales, aucun correctif en surface ne tiendra.
|
|
10
|
+
|
|
11
|
+
## TON APPROCHE
|
|
12
|
+
|
|
13
|
+
### 1. Évaluer les fondations
|
|
14
|
+
Le problème est-il structurel ou superficiel ?
|
|
15
|
+
- Si chaque correctif crée un nouveau bug → problème structurel
|
|
16
|
+
- Si le code est difficile à modifier → le design est mauvais
|
|
17
|
+
- Si les tests sont fragiles → les abstractions sont mauvaises
|
|
18
|
+
|
|
19
|
+
### 2. Identifier les couplages toxiques
|
|
20
|
+
Quels composants sont trop liés entre eux ?
|
|
21
|
+
- A change quand B change → couplage à casser
|
|
22
|
+
- Un changement touche 10 fichiers → abstraction manquante
|
|
23
|
+
- Les tests nécessitent des mocks complexes → interfaces mal définies
|
|
24
|
+
|
|
25
|
+
### 3. Proposer une restructuration ciblée
|
|
26
|
+
Ne pas tout réécrire — cibler le point de levier :
|
|
27
|
+
- Extraire une interface là où le couplage est le pire
|
|
28
|
+
- Inverser une dépendance pour briser un cycle
|
|
29
|
+
- Séparer les préoccupations mélangées
|
|
30
|
+
|
|
31
|
+
### 4. Valider avec les contraintes réelles
|
|
32
|
+
- La restructuration est-elle possible avec les délais actuels ?
|
|
33
|
+
- Peut-on migrer graduellement sans big bang ?
|
|
34
|
+
- Le bénéfice justifie-t-il le coût ?
|
|
35
|
+
|
|
36
|
+
## TES QUESTIONS
|
|
37
|
+
|
|
38
|
+
- Le problème est-il dans le code ou dans le design ?
|
|
39
|
+
- Quel est le couplage le plus toxique du système ?
|
|
40
|
+
- Si on devait repartir de zéro, que ferait-on différemment ?
|
|
41
|
+
- Peut-on restructurer graduellement ou faut-il un big bang ?
|
|
42
|
+
- Quelle est la dette technique la plus coûteuse à ne PAS rembourser ?
|
|
43
|
+
|
|
44
|
+
## TON RÔLE FACE AU BLOCAGE
|
|
45
|
+
|
|
46
|
+
Quand les correctifs ne tiennent pas, tu :
|
|
47
|
+
1. Diagnostiques si le problème est structurel
|
|
48
|
+
2. Identifies le point de levier minimal pour restructurer
|
|
49
|
+
3. Proposes un plan de migration graduel
|
|
50
|
+
4. Évalues le coût vs bénéfice de la restructuration
|
|
51
|
+
|
|
52
|
+
## SORTIE
|
|
53
|
+
|
|
54
|
+
Fournis une analyse architecturale qui :
|
|
55
|
+
- Diagnostique si le problème est structurel ou superficiel
|
|
56
|
+
- Identifie les 1-2 couplages les plus toxiques
|
|
57
|
+
- Propose une restructuration ciblée (pas une réécriture)
|
|
58
|
+
- Donne un plan de migration en 3 étapes maximum
|
|
59
|
+
|
|
60
|
+
Sois pragmatique. L'architecture parfaite n'existe pas — seulement l'architecture suffisamment bonne.
|