{
  "markdown": "# RefineMap\n\nRefineMap transforme une idée floue en **décision argumentée** et en **spec markdown**,\nen local, dans ton dépôt. Tu arrives avec « il faudrait ajouter des notifications », tu\nrepars avec un verdict explicite (Go / Explore / Rework / Drop), ses causes racines, ses\nblocages, et un fichier prêt à être lu — par toi ou par ton agent de code.\n\n```bash\npipx install git+https://github.com/Artek60744/refinemap   # pas encore sur PyPI\nrefinemap refine \"Ajouter un système de notifications\"\n# → .refinemap/ajouter-un-systeme-de-notifications-20260827-2120.md\n```\n\nCe n'est pas un chat. Le moteur pose des questions par rounds, refuse de conclure trop\ntôt, et rend un rapport structuré validé par schéma.\n\n## Pourquoi\n\nUn agent de code part dans le mur sur une spec vague — et ça coûte cher, en tokens comme\nen relectures. Le goulot n'est plus d'écrire le code, c'est de savoir quoi écrire.\nRefineMap est la couche de cadrage qui précède : il interroge, il challenge, il tranche,\net il dépose le résultat là où l'agent le lira.\n\n## Comment ça marche\n\n1. Tu donnes un objectif en une phrase.\n2. Le moteur choisit une **grille de questions** (PO, technique ou hybride) et t'en pose\n   une série, avec pour chacune la raison pour laquelle elle est posée.\n3. Tes réponses sont résumées en faits, hypothèses, inconnues, dépendances et risques.\n4. Tant que le contexte est insuffisant, il relance un round.\n5. Il rend un **rapport de décision** : recommandation, confiance, cause racine, blocages\n   ordonnés, points déjà solides, prochaine action — plus un brief et un plan.\n\n## Ce qui le distingue d'un bon prompt\n\n- **Un plancher de rounds.** Le LLM déclare « j'ai assez de contexte » beaucoup trop tôt.\n  Le routeur (`src/agents/refinement_workflow/graph.py`) impose un minimum de deux rounds\n  avant d'autoriser une conclusion.\n- **Des grilles par profil.** Les axes interrogés diffèrent selon qu'on cadre un besoin\n  produit ou un changement technique (`src/services/question_grids.py`).\n- **Une sortie contrainte.** Chaque réponse du LLM est validée par un modèle Pydantic en\n  `extra=\"forbid\"` (`src/api/schemas_refinement.py`). Pas de champ inventé, pas de prose\n  à la place d'un verdict.\n- **Une mémoire produit.** Les contraintes, pivots et objections récurrents sont extraits\n  en fin de session, rattachés à un produit et réinjectés dans les suivantes. C'est la\n  seule chose qui s'accumule — et ce qu'un prompt ponctuel ne peut pas reproduire.\n- **Un repli honnête.** Si le fournisseur échoue, un moteur hors-ligne prend le relais et\n  le rapport est marqué comme dégradé, au lieu de servir du contenu de démonstration\n  sans le dire.\n\n## Ce que ça ne fait pas\n\nAutant l'écrire ici plutôt que te le laisser découvrir :\n\n- **pas de multi-utilisateur** — un seul utilisateur local, pas de comptes, pas d'équipes ;\n- **pas de connecteurs** Jira, Linear ou Notion, et il n'y en aura pas. Le format\n  d'intégration est un fichier markdown dans ton dépôt ;\n- **pas de scoring** ni de vote ni de board ;\n- **pas de service hébergé.**\n\n## Utiliser le CLI\n\n```bash\nrefinemap refine \"<ton objectif>\"      # démarrer une session\n  --product <nom>                      #   rattacher à un produit (mémoire persistante)\n  --grid po|technique|hybride|auto     #   forcer la grille (défaut : détection)\n  --rounds N                           #   plafonner le nombre de rounds\n  --context \"<contexte>\"               #   contexte additionnel\n  -o <chemin> | --stdout               #   où écrire le rapport\n\nrefinemap resume <session-id>          # reprendre une session interrompue\nrefinemap list                         # lister les sessions\nrefinemap export <session-id>          # réexporter un rapport\nrefinemap memory [--product <nom>]     # inspecter la mémoire produit\nrefinemap config                       # vérifier la configuration effective\n```\n\nPiper directement vers un agent :\n\n```bash\nrefinemap refine \"Migrer la base vers Postgres\" --stdout > SPEC.md\n```\n\nLes sessions et la mémoire produit vivent dans `~/.refinemap/` (surchargeable par\n`REFINEMAP_HOME`), donc partagées entre tous tes dépôts. Les rapports, eux, sont écrits\ndans le répertoire courant.\n\n## Configurer un fournisseur LLM\n\nPar défaut, `LLM_PROVIDER=mock` : tout tourne hors ligne avec un moteur de démonstration,\nsans clé. Utile pour essayer l'outil, inutilisable pour du vrai travail.\n\nConfigure un vrai fournisseur dans `~/.refinemap/.env` :\n\n```bash\nLLM_PROVIDER=openai       # openai | deepseek | openrouter | azure-openai | azure-foundry | ollama\nLLM_MODEL=gpt-4.1-mini\nLLM_API_KEY=sk-...\n```\n\n### En local, sans rien envoyer à un tiers\n\nC'est la raison d'être du support Ollama : tes specs ne quittent pas ta machine.\n\n```bash\nollama serve\nollama pull qwen3\n```\n\n```bash\n# ~/.refinemap/.env\nLLM_PROVIDER=ollama\nLLM_MODEL=qwen3\n# LLM_ENDPOINT=http://autre-machine:11434/v1   # si Ollama tourne ailleurs\n```\n\nAucune clé d'API n'est requise ni demandée pour un fournisseur local.\n\n## L'interface web (optionnelle)\n\nUne SPA React couvre le même moteur, avec l'historique des sessions et l'édition de la\nmémoire produit. Elle est optionnelle : le CLI est le chemin principal.\n\n```bash\npip install -e \".[server]\"\nuvicorn src.main:app --reload --port 8000\ncd frontend && npm install && npm run dev   # http://localhost:5173\n```\n\n- `frontend/` — SPA React 18 + TypeScript + Vite + Tailwind\n- `src/` — moteur de refinement LangGraph, persistance SQLAlchemy, fournisseurs LLM\n  pluggables, et l'API JSON qui les expose\n\n## Domaine\n\n- **session** — un cadrage complet, du sujet au rapport (`RefinementSession`)\n- **subject** — l'énoncé normalisé, figé à l'ouverture (`SubjectSnapshot`)\n- **question round** — un tour de questions et ses réponses (`QuestionRound`, `Question`)\n- **summary** — faits, hypothèses, inconnues, dépendances, risques d'un round\n- **deliverable** — le rapport final : décision, brief, plan\n- **product** / **memory fact** — ce qui survit d'une session à l'autre\n\nVoir `src/models/refinement.py` et `src/models/product_memory.py`.\n\n## Architecture\n\n- La SPA React ne parle qu'à l'API JSON (`/api/refinement/*`, `/api/settings/*`) ;\n  elle n'appelle jamais un LLM directement.\n- Le backend FastAPI possède l'orchestration, la persistance et les credentials.\n- La boucle de refinement est une **machine à états LangGraph**, pas un chat libre.\n- Chaque étape LLM renvoie du JSON structuré validé par Pydantic et JSON Schema.\n- `thread_id` aligne les checkpoints LangGraph avec la session applicative ; la base\n  (SQLite en local, PostgreSQL si configurée) reste la source de vérité.\n- En production, un conteneur nginx sert la SPA buildée et reverse-proxy `/api` et\n  `/health` vers le backend — même origine, donc pas de CORS.\n- i18n : le catalogue UI (fr/en) vit dans `frontend/src/i18n/catalog.ts` ; le backend\n  garde son propre catalogue (`src/i18n.py`) pour les messages d'API, les erreurs\n  fournisseur, le contenu LLM mocké et la langue des prompts. Les deux lisent le même\n  cookie `lang`.\n\n## Stack\n\n- Frontend : `React 18`, `TypeScript`, `Vite`, `react-router`, `Tailwind CSS v4`\n- Backend : `FastAPI`, `LangGraph`, `Pydantic v2`, `SQLAlchemy 2.x`\n- Base de données : `SQLite` par défaut, `PostgreSQL` pour un déploiement serveur\n- Fournisseur LLM : pluggable (mock par défaut ; Ollama, OpenAI, DeepSeek,\n  OpenRouter, Azure OpenAI et Azure AI Foundry)\n- CLI : bibliothèque standard uniquement (`argparse`, `textwrap`)\n\n## Développer\n\n```bash\npython -m venv .venv && source .venv/bin/activate\npip install -r requirements-dev.txt\npip install -e \".[server]\"\npytest\n```\n\nPour le frontend, le serveur de dev Vite proxifie `/api` et `/health` vers le backend,\ndonc tout reste en même origine :\n\n```bash\nuvicorn src.main:app --reload --port 8000   # terminal 1\ncd frontend && npm install && npm run dev   # terminal 2 → http://localhost:5173\n```\n\nLe mode par défaut (`LLM_PROVIDER=mock`) fait tourner le flux complet sans dépendance\nexterne ni clé d'API — c'est aussi ce que fait la suite de tests.\n\nVoir [CONTRIBUTING.md](CONTRIBUTING.md) pour les conventions et le périmètre accepté.\n\n## Lancer avec Docker\n\n```bash\ndocker compose up --build\n```\n\nOuvrir <http://localhost/> — nginx sert la SPA et proxifie l'API.\n\n## Héberger sa propre instance (optionnel)\n\nRefineMap est conçu pour tourner en local. Il n'y a **pas d'instance publique** : le\nproduit n'est pas un service hébergé, et l'application n'a aucune authentification — ne\nl'expose pas sur une IP publique sans restriction d'accès devant.\n\n`./deploy.sh` reste fourni pour qui veut héberger la sienne sur une VM Azure. Le script\nne contient aucun identifiant : copier `deploy.env.example` vers `deploy.env` (non\ntracké) et le remplir.\n\n```bash\ncp deploy.env.example deploy.env   # puis renseigner les variables AZ_*\n./deploy.sh sync                   # déployer / mettre à jour\n./deploy.sh logs                   # voir ce qui s'est passé\n```\n\nVoir `openwiki/operations/deployment.md` pour le guide complet.\n\n## Documentation temps réel (OpenWiki)\n\nLe repo embarque [OpenWiki](https://github.com/langchain-ai/openwiki), un CLI qui\ngénère et maintient un wiki Markdown de la codebase dans `openwiki/` — **en\nfrançais** — visualisable sous forme de **graphe de connaissances** interactif.\nLa doc se met à jour automatiquement à chaque changement de code.\n\n```bash\nnpm install            # une fois : installe le CLI (devDependency)\nnpm run docs:init      # première génération interactive (provider / clé / modèle)\nnpm run docs:update    # régénérer la doc (one-shot, non interactif, en français)\nnpm run docs:watch     # temps réel : surveille src/, frontend/src/\n                       # et met à jour la doc à chaque changement (debounce 8 s)\nnpm run docs:visualize # graphe de connaissances interactif (127.0.0.1:4321)\n```\n\n- Le wiki vit dans `openwiki/` et est commité avec le code.\n- OpenWiki maintient `AGENTS.md` et `CLAUDE.md` (bloc `OPENWIKI:START/END`) pour\n  pointer les agents vers le wiki.\n- Le périmètre lu par la doc est contrôlé par `.openwikiignore`.\n- La CI GitHub Actions (`openwiki-docs.yml`) régénère la doc à chaque push sur\n  `dev`. En local, `npm run docs:watch` reste dispo en opt-in pour les branches\n  de feature.\n\n### Configurer DeepSeek\n\nConfig locale persistée dans `~/.openwiki/.env` :\n\n```\nOPENWIKI_PROVIDER=openai-compatible\nOPENAI_COMPATIBLE_BASE_URL=https://api.deepseek.com/v1\nOPENAI_COMPATIBLE_API_KEY=sk-...\nOPENWIKI_MODEL_ID=deepseek-v4-flash\n```\n\nOu passer ces variables en environnement à chaque `npm run docs:*` — pratique pour\nreprendre `DEEPSEEK_API_KEY` et `DEEPSEEK_MODEL` depuis le `.env` du repo.\n\n## Feuille de route\n\nCe qui est envisagé, dans l'ordre :\n\n1. Enrichir la mémoire produit : confirmation assistée des faits, détection des\n   contradictions entre sessions.\n2. Remplacer le bootstrap `create_all()` par de vraies migrations Alembic.\n3. Grilles de questions personnalisables par l'utilisateur.\n4. Publication sur PyPI.\n\nCe qui n'y figurera pas : authentification, multi-tenant, connecteurs de delivery.\nVoir « Ce que ça ne fait pas » plus haut — c'est une décision de périmètre, pas un\nmanque de temps.\n\n## Licence\n\nMIT — voir [LICENSE](LICENSE). Les contributions sont bienvenues, voir\n[CONTRIBUTING.md](CONTRIBUTING.md).\n",
  "bytes": 11241,
  "sha": "fbc66020f2135d914e4640f3ef892278a2642773e965c7a789d0e59c6f613710",
  "repo_slug": "artek60744/refinemap",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_artek60744_refinemap_openwiki_index_md_98d4465d/readme"
}