SLOPSHOPPER

solomap-observer

Keep SoloMap conversations available after each reply.

newprocess
A shopper browsing a rack in a slop shop
README

<img src="https://raw.githubusercontent.com/jobssteve164dev/solopreneur-roadmap/main/resources/logo_with_text.png" width="320" alt="SoloMap Logo" />

<h1 align="center">SoloMap - AI Coding Agent Roadmap</h1>

<strong>English</strong> | <a href="https://github.com/jobssteve164dev/solopreneur-roadmap/blob/main/README.zh-CN.md">简体中文</a>

<strong>Stop losing momentum in scattered AI chats. Turn your local folder into a visual cockpit for autonomous agents.</strong>

<a href="https://solomap.app"><img src="https://img.shields.io/badge/Website-solomap.app-c92f38?style=flat-square" alt="SoloMap website" /></a> <a href="https://marketplace.visualstudio.com/items?itemName=SZLK.solopreneur-roadmap"><img src="https://img.shields.io/badge/VS%20Code-Marketplace-blue?style=flat-square&logo=visual-studio-code" alt="Marketplace" /></a> <a href="https://github.com/jobssteve164dev/solopreneur-roadmap/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-MIT-emerald?style=flat-square" alt="License" /></a> <a href="https://github.com/jobssteve164dev/solopreneur-roadmap"><img src="https://img.shields.io/badge/Git-Friendly-purple?style=flat-square&logo=git" alt="Git Friendly" /></a>


🤯 Are you suffering from "AI Chat Hell"?

  1. Scattered Context: You talk to AI in 20 different chat windows. A week later, you have no idea what the agent changed, where the project is stuck, or what to do next.
  2. Black Box Execution: You run a terminal agent, it generates 500 lines of code, breaks 3 features, and leaves you to diff files line-by-line.
  3. Cloud Lock-in & Privacy Risks: You just want a clear task manager, but other tools force you to upload your roadmap, tasks, and private code to their proprietary clouds.

🚀 Introducing SoloMap: The local command deck above your AI tools

SoloMap is a local-first, Git-friendly, highly-polished execution control panel built directly inside VS Code. It does not replace your favorite Agent CLIs (like Claude Code, agy, or Codex) — it orchestrates them.


💡 Core Capabilities

🧭 Visual Coding Roadmap

  • From Idea to Milestones: Generate a step-by-step developer roadmap from your initial project idea, structured through Build ➔ Sell ➔ Learn ➔ Improve.
  • Git-Friendly CSV: Saved in .solopreneur/roadmap.csv. Every status update or step adjustment is a plain text diff. Zero database lock-in.

🤖 Local Agent Orchestrator

  • One-Click Run: Dispatch tasks to your local CLI agents (agy, codex, claude-code, copilot-cli, grok) directly from the active roadmap step.
  • Step-Level Handover: Automatically builds a context-rich .solopreneur/step-memory/ package before each execution so agents know the exact scope and completion criteria.
  • Multi-Agent Collaboration: Toggle a secondary Agent (e.g., use agy for building and claude for read-only review) to get automatic code quality gates.

🧠 Cross-Project Learning & Memory

  • Never Make the Same Mistake Twice: Lessons learned, architectural decisions, and repeated blockers are stored in SoloMap's unified local database and retrieved through the Runtime for each relevant task.
  • Privacy by Default: All task logs, agent histories, and learnings live entirely on your machine.

🏁 Quick Start

Get started in less than 60 seconds. All you need is a local folder and your favorite Agent CLI.

  1. Install the SoloMap VS Code Extension.
  2. Open Command Palette (Cmd/Ctrl + Shift + P) and run SoloMap: Show AI Roadmap.
  3. Register Project: Choose your local project folder and select the project type.
  4. Bootstrapping: In the initial step, type your project goal and let the agent generate your first runnable .solopreneur/roadmap.csv.
  5. Execute & Deliver: Expand any roadmap node, dispatch a local agent, run verification, and keep the project moving forward!

🛠️ Integrated Agent CLIs

SoloMap runs your local CLI agents via VS Code's integrated terminal for maximum transparency. We auto-detect:

  • Antigravity (agy)
  • Codex (codex-cli)
  • Claude Code (claude-code)
  • GitHub Copilot (copilot-cli)
  • OpenCode (opencode)
  • Grok Build (grok)
  • Custom executables are fully supported in SoloMap settings.

🔒 Privacy & Architecture

SoloMap creates a .solopreneur/ folder inside your project root to keep it completely self-contained:

.solopreneur/
  ├── roadmap.csv          <- The single source of truth for your roadmap (Git-friendly)
  ├── step-memory/         <- Context & completion criteria for each roadmap node
  └── agent-runs/          <- Minimal live task recovery and report files

.solomap-global/
  └── solomap.db           <- Shared conversations, run indexes, artifacts, growth data, and memory

📖 Methodology & Advanced Docs

For solo founders looking to build a highly reproducible delivery machine, explore our core blueprints:


💖 Support and Feedback

We are building SoloMap in public for solo developers. Your feedback directly shapes the product!

  • Love SoloMap? Please leave a ⭐ Marketplace Rating & Review to help other solo developers find us!
  • Having trouble? Open a GitHub Issue or submit a Seed User Feedback.
  • Contribute & Reward: If you contribute to this project's source code or if your submitted issue/feedback is adopted, please contact hello@szlk.ai. Once verified, you will be rewarded with a 1-year Pro membership!
Source 1 files
hooks/register.js 76 lines
1async function send($, action, event) {
2  const node = await $.env.get('SOLOMAP_NODE_EXECUTABLE');
3  const checkpoint = await $.env.get('SOLOMAP_TASK_COMMAND');
4  if (!node || !checkpoint) return;
5  for (;;) {
6    try {
7      const result = await $.process.run([node, checkpoint, action], { stdin: JSON.stringify(event), timeoutMs: 600000 });
8      if (result.exitCode === 0) return result;
9      if (result.exitCode === 3) return;
10    } catch {}
11    await $.clock.sleep(250);
12  }
13}
14
15export function register(on) {
16  let pendingUser = '';
17  let active;
18  let sequence = 0;
19  let ready = false;
20  on('session.start', async ($, e, next) => {
21    const result = await next(e);
22    const receipt = await send($, 'native-ready', { schemaVersion: 1, sessionId: await $.session.id() });
23    if (receipt) {
24      ready = true;
25      try {
26        const saved = JSON.parse(receipt.stdout);
27        sequence = Number(saved.nextSequence) - 1;
28        active = saved.resume?.active;
29        pendingUser = saved.resume?.pendingUser || '';
30      } catch { sequence = 0; }
31    }
32    return result;
33  });
34  on('session.append', async ($, e, next) => {
35    if (!e.agentId && e.uuid) {
36      const message = e.message;
37      if (e.door === 'prompt' && message.type === 'user' && !message.isMeta) {
38        await send($, 'native-append', { schemaVersion: 1, kind: 'prompt', sessionId: await $.session.id(), uuid: e.uuid });
39        pendingUser = e.uuid;
40      }
41      if (e.door === 'response' && active && message.type === 'assistant' && message.role === 'assistant') {
42        const turn = active;
43        await send($, 'native-append', { schemaVersion: 1, kind: 'assistant', sessionId: await $.session.id(), uuid: e.uuid, userUuid: turn.userUuid, providerTurnId: turn.providerTurnId });
44        if (!turn.assistantUuids.includes(e.uuid)) turn.assistantUuids.push(e.uuid);
45      }
46    }
47    return next(e);
48  });
49  on('turn.start', async ($, e, next) => {
50    const result = await next(e);
51    if (!e.agentId && pendingUser) {
52      if (!ready) {
53        const receipt = await send($, 'native-ready', { schemaVersion: 1, sessionId: await $.session.id() });
54        if (receipt) {
55          ready = true;
56          try { sequence = Number(JSON.parse(receipt.stdout).nextSequence) - 1; } catch { sequence = 0; }
57        }
58      }
59      active = { providerTurnId: e.turnId, userUuid: pendingUser, assistantUuids: [], startedAt: new Date(await $.clock.now()).toISOString() };
60      pendingUser = '';
61      await send($, 'native-event', { schemaVersion: 1, phase: 'start', sequence: ++sequence, sessionId: await $.session.id(), ...active, completedAt: active.startedAt, reason: 'answer' });
62    }
63    return result;
64  });
65  on('turn.complete', async ($, e, next) => {
66    const result = await next(e);
67    if (!e.agentId && active?.providerTurnId === e.turnId) {
68      const event = { schemaVersion: 1, phase: 'complete', sequence: ++sequence, sessionId: await $.session.id(), ...active,
69        completedAt: new Date(await $.clock.now()).toISOString(), reason: e.isAborted ? 'aborted' : e.reason };
70      active = undefined;
71      await send($, 'native-event', event);
72    }
73    return result;
74  });
75}
76