AI coding assistants are becoming part of the developer workflow, but most of their context disappears when the session ends. Claude Code, Codex, Cursor, OpenCode, and similar tools often leave behind rich local histories: prompts, assistant responses, tool calls, file edits, failed attempts, and design decisions. PromptGhost turns that trail into a durable memory system.
PromptGhost continuously ingests AI coding history, stores structured memories in SQLite, consolidates them over time, and exposes a special Ghost Mode: a persona that answers as the accumulated developer-self emerging from your sessions.
The Core Idea
The project started from the Always On Memory Agent architecture: a lightweight background memory system with:
- an
IngestAgent - a
ConsolidateAgent - a
QueryAgent - SQLite storage
- a file watcher
- a Streamlit dashboard
PromptGhost extends that base rather than replacing it. The original flow still works: drop files in ./inbox, let the agent ingest them, periodically consolidate, and query the memory store.
The extension adds a new source of memory: real CLI AI coding histories.
Why CLI Coding History Is Valuable
AI coding sessions contain more than final code. They capture:
- what the developer asked for
- what tradeoffs were discussed
- which files and tools were used
- which approaches failed
- what the developer repeatedly cares about
- what kind of feedback the developer accepts or rejects
That is enough signal to build a practical "second self" for development work. Not a mystical clone, just a memory layer that can recognize recurring engineering behavior.
Architecture
The Main Components
agent.py
agent.py is the runtime entry point. It owns:
- provider selection
- the original ADK agents
- the OpenAI-compatible fallback runtime
- the file watcher
- the PromptGhost watcher
- consolidation loops
- HTTP routes
The key design decision was to keep Gemini ADK as the original path and add OpenAI compatibility without pretending every provider supports ADK the same way.
parser.add_argument(
"--provider",
choices=["gemini", "openai", "openai-compatible"],
default=PROVIDER,
help="LLM provider (default: gemini). openai-compatible uses /v1/chat/completions.",
)
Gemini mode uses the base ADK orchestration. OpenAI-compatible mode uses the same SQLite tools directly.
promptghost.py
promptghost.py contains the Ghost-specific extension logic:
- default CLI history globs
- JSONL discovery
- defensive parsing
- normalized
GhostTurnrecords -
ghost_eventsandghost_reflectionstables - Markdown export
The parser needs to be loose because each coding tool stores history differently.
def parse_jsonl_history(path: Path, max_turn_chars: int = 12000) -> list[GhostTurn]:
turns: list[GhostTurn] = []
session_id = path.parent.name or path.stem
lines = path.read_text(encoding="utf-8", errors="replace").splitlines()
for line in lines:
if not line.strip():
continue
try:
item = json.loads(line)
except json.JSONDecodeError:
continue
turns.extend(_turns_from_event(item, str(path), session_id, max_turn_chars))
return turns
Each event becomes one stable shape:
@dataclass
class GhostTurn:
source_path: str
session_id: str
role: str
content: str
tool_name: str = ""
created_at: str = ""
raw: str = ""
dashboard.py
The Streamlit dashboard adds a dedicated PromptGhost tab:
- Ghost avatar
- query box
- sample prompts
- Ghost Reflection button
- reflection feed
- recent ghost signals
- Markdown export
The dashboard also shows the active provider and model so users know whether the backend is running on Gemini, OpenAI, or a compatible endpoint.
Provider Abstraction
PromptGhost supports three runtime modes.
python agent.py --provider gemini --enable-ghost
python agent.py --provider openai --model gpt-4.1-mini --enable-ghost
python agent.py \
--provider openai-compatible \
--openai-base-url http://localhost:1234/v1 \
--model local-model \
--enable-ghost
The OpenAI-compatible runtime posts to /v1/chat/completions:
payload = {
"model": self.model,
"messages": [
{"role": "system", "content": system},
{"role": "user", "content": user},
],
"temperature": temperature,
}
Structured tasks request JSON when supported:
payload["response_format"] = {"type": "json_object"}
Some local servers reject response_format, so the implementation retries with a stricter prompt:
try:
content = await self._chat(system, user, response_format={"type": "json_object"})
except RuntimeError:
content = await self._chat(
system + "\nReturn valid JSON only. Do not wrap it in Markdown.",
user,
response_format=None,
)
This makes PromptGhost usable with hosted providers, local model servers, and enterprise gateways.
Memory Without a Vector Database
PromptGhost intentionally stores structured memory in SQLite. The core tables are:
CREATE TABLE IF NOT EXISTS memories (
id INTEGER PRIMARY KEY AUTOINCREMENT,
source TEXT NOT NULL DEFAULT '',
raw_text TEXT NOT NULL,
summary TEXT NOT NULL,
entities TEXT NOT NULL DEFAULT '[]',
topics TEXT NOT NULL DEFAULT '[]',
connections TEXT NOT NULL DEFAULT '[]',
importance REAL NOT NULL DEFAULT 0.5,
created_at TEXT NOT NULL,
consolidated INTEGER NOT NULL DEFAULT 0
);
PromptGhost adds:
CREATE TABLE IF NOT EXISTS ghost_events (
id INTEGER PRIMARY KEY AUTOINCREMENT,
source_path TEXT NOT NULL,
session_id TEXT NOT NULL,
role TEXT NOT NULL,
content TEXT NOT NULL,
tool_name TEXT NOT NULL DEFAULT '',
created_at TEXT NOT NULL,
raw_json TEXT NOT NULL DEFAULT ''
);
And daily reflections:
CREATE TABLE IF NOT EXISTS ghost_reflections (
id INTEGER PRIMARY KEY AUTOINCREMENT,
reflection_date TEXT NOT NULL,
summary TEXT NOT NULL,
developer_patterns TEXT NOT NULL DEFAULT '[]',
sharp_edges TEXT NOT NULL DEFAULT '[]',
created_at TEXT NOT NULL
);
The benefit is operational simplicity. There is no vector database to run, no embedding index to rebuild, and no external service required for persistence.
Ghost Mode
Ghost Mode is driven by a strong system prompt:
You are PromptGhost: the accumulated developer-self of the user, reconstructed
from their real CLI AI coding sessions.
Speak as the user's second self, not as a generic assistant. Be specific,
evidence-based, and slightly uncanny: notice recurring engineering instincts,
blind spots, taste, pace, tool preferences, and the kinds of problems the user
keeps returning to. Never invent private facts. If the memory is thin, say the
ghost is still forming.
The important part is evidence. Ghost Mode should cite stored ghost events rather than inventing personality traits.
Example query:
curl "http://localhost:8888/ghost/query?q=what+do+I+repeatedly+overthink"
Example response shape:
You tend to pause around integration boundaries: provider adapters, file watchers,
and persistence behavior. The recurring instinct is not "add a feature," but
"make sure the feature does not replace the core contract" [Ghost 12] [Ghost 18].
The Watch Loop
The Ghost watcher periodically discovers supported history files:
DEFAULT_GHOST_PATTERNS = [
"~/.claude/projects/**/*.jsonl",
"~/.codex/sessions/**/*.jsonl",
"~/.opencode/**/*.jsonl",
"~/.opencode/**/session*.json",
"~/.cursor/**/*.jsonl",
]
Then it parses and ingests them:
for turn in turns:
if promptghost.store_ghost_turn(DB_PATH, turn):
if turn.role in {"user", "assistant", "tool"}:
await agent.ingest(turn.to_memory_text(), source=f"PromptGhost:{f.name}")
That means every ghost event is stored in ghost_events, and useful turns are also fed into the main memory system for normal consolidation and querying.
API Surface
PromptGhost adds these endpoints:
| Endpoint | Method | Purpose |
|---|---|---|
/ghost/query?q=... |
GET | Talk to your Ghost |
/ghost/reflect |
POST | Generate a daily Ghost Reflection |
/ghost/status |
GET | Read recent ghost events and reflections |
/ghost/export |
GET | Export shareable Markdown insights |
Normal memory endpoints remain available:
| Endpoint | Method | Purpose |
|---|---|---|
/ingest |
POST | Add text memory |
/query?q=... |
GET | Query memory |
/consolidate |
POST | Run consolidation |
/memories |
GET | Browse memory |
/status |
GET | Runtime status |
Privacy and Safety
PromptGhost reads local AI coding histories, which can include:
- source snippets
- private file paths
- business logic
- prompts
- tool calls
- accidental secrets
For that reason:
-
memory.dbis ignored by Git. -
.envfiles are ignored by Git. - local inbox contents are ignored by Git.
- generated exports should be reviewed before sharing.
For sensitive teams, run PromptGhost against a local model or enterprise OpenAI-compatible gateway.
What I Would Add Next
The next useful features are straightforward:
- parser fixtures for every supported coding tool
- a privacy scrubber before storage
- per-project Ghost identities
- custom
--ghost-patternflags - encrypted archive export/import
- retention policies and forgetting
- shareable image cards for Ghost Insights
- Docker Compose for one-command startup
- optional SQLite FTS or embeddings for larger memory stores
Final Thoughts
PromptGhost is not trying to make an AI assistant magically know you. It takes a more practical route: read the actual sessions where you collaborated with AI tools, compress them into durable memory, and expose the patterns back to you.
That is enough to make coding assistants feel less stateless and more continuous.
Screenshots
Code & more: https://www.dailybuild.xyz/project/198-prompt-ghost





Top comments (0)