
A persistent memory layer for Claude that combines short-term key-value storage with Q-promise deduplication to avoid redundant operations. Built as a companion to the PPM Python package manager, it integrates Context+ semantic memory graphs to maintain conversation state and project context across sessions. Reach for this when you need Claude to remember decisions, cache expensive computations, or maintain awareness of prior work without re-processing. The MCP exposes stdio transport and plugs into Claude Desktop or any MCP-compatible client. Useful for long-running agent tasks where context continuity matters more than ephemeral chat.
pypm packaging CLI with shared PMLL memory + Q-promise. Sibling: drQedwards/pmll.
Live Stellar pmll-anchor IDs: docs/STELLAR.md · skills: SKILL.md · promises: Q_promise_lib/README.md.
TL;DR: PPM packages Python (C CLI). Shared PMLL owns memory/state (
memory_silo_t, exactpeek+ semanticpeek_semantic, SAT bridge,init_pml). Q-promise owns temporal/control-flow (qpromise_*,libqpromise.so) — it does not replace the silo. Optional Stellar commitments hash off-chainCodeworkPayloads into 32-byte digests viapmll-anchor(ABI: init/store/get/bump). Companion packaging CLI + MCP memory server live in-tree.
PMLL provides durable structured memory for agent workflows, alongside a PPM packaging CLI (hermetic bundles, plugins, signing) and the PMLL Memory MCP server. Long-term graph tools adapt Context+.
Two complementary layers — not substitutes for each other:
| Layer | Owns | Key surface |
|---|---|---|
| PMLL | Durable memory / state | memory_silo_t, peek / peek_semantic, silo_set, SAT bridge, init_pml |
| Q-promise | Temporal / control-flow | qpromise_* API, libqpromise.so, deferred qpromise_drain() |
Q-promise does not replace the silo. A promise may reference a memory key (and optional SAT state id); results are committed back with silo_set / qpromise_resolve_commit.
retrieve (peek / peek_semantic)
→ compute / request work
→ promise PENDING
→ resolve / reject (optionally resolve_commit → silo)
→ continuation (then / catch / finally via qpromise_drain)
→ memory update
→ retrieve again
Thread safety: the C Q-promise drain is single-threaded. Continuations run only during qpromise_drain() on the calling thread; callers must externally serialize access. Details: Q_promise_lib/README.md.
Headers: PMLL.h · implementation: PMLL.c
| Symbol | Role |
|---|---|
memory_silo_t | Associative/semantic silo: tree, slots[], embed_dim (PMLL_EMBED_DIM=32), slot_count |
silo_slot_t | key, content, embedding, resolved |
init_silo / free_silo / silo_set | Allocate, free, write key/content + embedding |
peek | Exact key, else index |
peek_semantic | Cosine ≥ min_sim over embeddings (silo_embed_text, silo_cosine_similarity) |
init_pml | Sets every assignment[i] = -1 (undecided) |
check_conflict | Treats -1 as undecided (not sticky false from zero-fill) |
sat_bridge_* | Map 3SAT tokens → associative string literals in the silo |
Build / test / API: Q_promise_lib/README.md (authoritative). Public symbols are qpromise_*; shared object is libqpromise.so. The old prototype (QMemNode / q_mem_* / memory-chain walker) is removed; Q_promises.h is a compatibility include redirecting to qpromise.h.
| Command | What it does |
|---|---|
pypm doctor | Checks Python headers, C compiler, OpenSSL, WASI toolchain, GPU, … |
pypm sandbox [-d DIR] | Drops you into an ephemeral temp dir (or custom DIR) with a full shell |
pypm plugin add NAME SRC | Downloads a .so plugin (from URL or path) into ~/.pypm/plugins/ |
pypm plugin run NAME … | Executes pypm_plugin_main() inside the named plugin |
pypm pypylock [-o FILE] | Bundles every wheel + interpreter into dist/venv.tar.gz (or FILE) |
pypm version | Prints the current CLI version |
ppm import PKG | Import and cache a package with GPU-accelerated hash verification |
ppm add PKG --lock | Add packages and update the lockfile |
ppm plan / ppm apply | Plan dependency changes, then apply them with an audit trail |
ppm snapshot / ppm rollback | Snapshot the environment; roll back to any prior state |
ppm sign / ppm verify | Sign artifacts (Ed25519) and verify cryptographic receipts |
ppm sbom | Generate a Software Bill of Materials (SBOM) |
Road-mapped: SAT dependency solver, parallel wheel cache, workspaces with single lockfile, WASM wheel resolution, Conda & Poetry import plugins.
gcc, clang, or MSVC)libcurl (plugin downloads)libdl (dynamic loading — standard on Linux / macOS)tar / libarchive (optional, for pypylock bundles)git clone https://github.com/drQedwards/PPM.git
cd PPM
cc -Wall -Wextra -ldl -lcurl -o pypm Ppm.c
./pypm doctor # Diagnose your dev box
./pypm sandbox # Spin up a throw-away REPL playground
cd Q_promise_lib
make clean && make test
make shared # → libqpromise.so
nvcc -O3 CLI/CLI.cu -lcuda -o ppm-gpu
./ppm-gpu import transformers torch --verbose
# Import a single package
ppm import transformers
# Import with a specific version
ppm import transformers==4.43.3
# Import multiple packages
ppm import transformers torch numpy
# Scan a Python file for imports and install them
ppm import --from-file my_script.py
# Verbose — watch what's happening
ppm import transformers --verbose
# 🔍 Resolving transformers...
# ⬇️ Downloading transformers-4.43.3-py3-none-any.whl
# 🔐 GPU integrity check: PASSED
# ✅ transformers==4.43.3 imported successfully
ppm init
# Creates:
# .ppm/
# ├── ledger.jsonl ← append-only operation log
# ├── state.json ← current state
# ├── lock.json ← dependency lockfile
# └── snapshots/ ← rollback points
ppm add transformers torch==2.4.0 --lock
ppm plan
# { "plan": "install", "packages": { "transformers": "4.43.3", ... } }
ppm apply --note "Added ML stack"
ppm snapshot --name "before-upgrade"
ppm snapshots
ppm rollback before-upgrade
ppm doctor
# ✅ Python dev headers found
# ✅ C compiler available
# ✅ CUDA toolkit available
# 🏁 Diagnostics complete (0 issues found)
ppm sandbox # ephemeral temp directory
ppm sandbox -d /tmp/mydir # custom directory
ppm pypylock -o production-env.tar.gz
ppm import torch --verbose
# 🚀 GPU hash verification: SHA-256 computed on device
# ✅ Integrity verified: e3b0c44298fc1c149afbf4c8996fb924...
ppm ensure transformers --gpu auto # auto-detect CUDA
ppm ensure transformers --gpu cu121 # force CUDA 12.1
ppm ensure transformers --gpu cpu # CPU-only
ppm keygen --out-priv ed25519.priv --out-pub ed25519.pub
ppm sign --sk ed25519.priv --file torch-2.4.0-*.whl --gpu ./libbreath_gpu.so
ppm verify --receipt torch-2.4.0-*.whl.receipt.json --file torch-2.4.0-*.whl
ppm sbom --out project-sbom.json
ppm provenance --out provenance.json
ppm graph --dot | dot -Tpng -o deps.png
# Install a plugin
ppm plugin add auditwheel https://cdn.example.com/auditwheel.so
# Run it
ppm plugin run auditwheel repair --wheel torch-2.4.0-cp310-linux_x86_64.whl
// hello.c
#include <stdio.h>
int pypm_plugin_main(int argc, char **argv) {
puts("Hello from a plugin 👋");
return 0;
}
cc -shared -fPIC -o hello.so hello.c
mv hello.so ~/.pypm/plugins/
pypm plugin run hello
pypm.toml[tool.ppm]
python = "^3.10"
default_gpu = "auto"
[tool.ppm.backends]
cpu.index = "https://download.pytorch.org/whl/cpu"
cu121.index = "https://download.pytorch.org/whl/cu121"
cu122.index = "https://download.pytorch.org/whl/cu122"
torch_prefer = "2.4.*"
transformers_prefer = "4.43.*"
export PYP_WORKSPACE_ROOT=/path/to/project # override workspace detection
export PYP_DEBUG=1 # enable debug output
export CUDA_VISIBLE_DEVICES=0 # control GPU usage
Persistent memory logic loop with short-term KV context memory, Q-promise deduplication, and Context+ long-term memory graph designed to improve context retention and retrieval for coding agents.
pmll-memory-mcp is a Model Context Protocol (MCP) server with complementary
short-term KV and optional long-term graph layers. Server construction prefers
MCPServer (mcp 2.x) and falls back to FastMCP (mcp 1.x) — see
mcp/pmll_memory_mcp/server.py.
Ground tool names in code: TypeScript (mcp/src/index.ts) has 15 tools including
graphql and names like create_relation; Python (mcp/pmll_memory_mcp/server.py)
has 14 tools (no graphql) with several longer names such as create_memory_relation.
A ctypes demo in Ppm-lib/pmll_mcp/ loads libqpromise.so via qpromise_*.
Memory layers:
PMLL.c::memory_silo_t.The server is designed to be the 3rd initializer alongside Playwright and other MCP tools — loaded once at the start of every agent task. Agents call init once at task start, then use peek before any expensive MCP tool invocation to avoid redundant calls. Frequently accessed entries are promoted to the long-term memory graph for semantic retrieval across sessions (SQLite-backed graph).
Tool counts differ by implementation (TS 15 incl. graphql; Python 14 — see note above). Historical docs below list the TypeScript tool surface.
Modern Claude agent tasks routinely call Playwright, file-system tools, and other MCP servers. Without a shared memory layer, every subtask re-initializes the same context from scratch. pmll-memory-mcp eliminates this overhead with two complementary memory layers:
Agent task start
├── 1st init: Playwright MCP
├── 2nd init: Unstoppable Domains MCP (see unstoppable-domains/)
└── 3rd init: pmll-memory-mcp ← this server
├── Short-term: all tool calls go through peek() first
└── Long-term: frequently accessed entries auto-promote to graph
peek() patternBefore every expensive MCP tool invocation, agents call peek to check the cache:
// Pseudocode — what the agent does automatically via MCP tool calls
// 1. Check cache before navigating
const result = mcp.call("pmll-memory-mcp", "peek", { session_id: sid, key: "https://example.com" });
if (result.hit) {
const pageContent = result.value; // ← served from PMLL silo, no browser needed
} else {
// 2. Cache miss — do the real work
const pageContent = mcp.call("playwright", "navigate", { url: "https://example.com" });
// 3. Populate the cache for future agents / subtasks
mcp.call("pmll-memory-mcp", "set", {
session_id: sid,
key: "https://example.com",
value: pageContent,
});
}
| Tool | Input | Output | Description |
|---|---|---|---|
init | session_id: str, silo_size: int = 256 | {status, session_id, silo_size} | Set up PMLL silo + Q-promise state for session |
peek | session_id: str, key: str | {hit, value?, index?} or {hit, status, promise_id} | Non-destructive cache + promise check |
set | session_id: str, key: str, value: str | {status: "stored", index} | Store KV pair in the silo |
resolve | session_id: str, promise_id: str | {status: "resolved"|"pending", payload?} | Check/resolve a Q-promise continuation |
flush | session_id: str | {status: "flushed", cleared_count} | Clear all silo slots at task completion |
| Tool | Input | Output | Description |
|---|---|---|---|
graphql | query: str, variables?: object, operationName?: str | {data} or {errors} | Execute GraphQL queries/mutations against the memory store |
These tools are adapted from Context+ by @ForLoopCodes, providing SQLite-backed semantic memory with graph traversal, decay scoring, and cosine similarity search.
| Tool | Input | Output | Description |
|---|---|---|---|
upsert_memory_node | session_id, type, label, content, metadata? | {node} | Create or update a memory node with auto-generated TF-IDF embeddings |
create_relation | session_id, source_id, target_id, relation, weight?, metadata? | {edge} | Create typed edges (relates_to, depends_on, implements, references, similar_to, contains) |
search_memory_graph | session_id, query, max_depth?, top_k?, edge_filter? | {direct, neighbors, totalNodes, totalEdges} | Semantic search with graph traversal — direct matches + neighbor walk |
prune_stale_links | session_id, threshold? | {removed, remaining} | Remove decayed edges (e^(-λt) below threshold) and orphan nodes with low access |
add_interlinked_context | session_id, items[], auto_link? | {nodes, edges} | Bulk-add nodes with auto-similarity linking (cosine ≥ 0.72 creates edges) |
retrieve_with_traversal | session_id, start_node_id, max_depth?, edge_filter? | [{node, depth, pathRelations, relevanceScore}] | Walk outward from a node — returns reachable neighbors scored by decay & depth |
| Tool | Input | Output | Description |
|---|---|---|---|
resolve_context | session_id, key | {source, value, score} | Unified context lookup: short-term KV → long-term graph → miss |
promote_to_long_term | session_id, key, value, node_type?, metadata? | {promoted, nodeId} | Promote a short-term KV entry to the long-term memory graph |
memory_status | session_id | {shortTerm, longTerm, promotionThreshold} | Unified view of short-term KV and long-term graph memory status |
npx (recommended — no install needed)npx pmll-memory-mcp
npm install -g pmll-memory-mcp
pmll-memory-mcp # starts the stdio MCP server
pip install pmll-memory-mcp
pmll-memory-mcp # starts the stdio MCP server
claude_desktop_config.json){
"tools": [
{
"name": "init",
"description": "Set up PMLL silo and Q-promise state for a session. Call once at task start.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"silo_size": { "type": "integer", "default": 256 }
},
"required": ["session_id"]
}
},
{
"name": "peek",
"description": "Non-destructive cache lookup + Q-promise check. Call before every expensive MCP tool invocation.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"key": { "type": "string" }
},
"required": ["session_id", "key"]
}
},
{
"name": "set",
"description": "Store a key-value pair in the session silo. Call after a cache miss.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"key": { "type": "string" },
"value": { "type": "string" }
},
"required": ["session_id", "key", "value"]
}
},
{
"name": "resolve",
"description": "Check or resolve a Q-promise continuation by promise ID.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"promise_id": { "type": "string" }
},
"required": ["session_id", "promise_id"]
}
},
{
"name": "flush",
"description": "Clear all silo slots for a session. Call at task completion.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" }
},
"required": ["session_id"]
}
},
{
"name": "graphql",
"description": "Execute GraphQL queries or mutations against the memory store.",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" },
"variables": { "type": "object" },
"operationName": { "type": "string" }
},
"required": ["query"]
}
},
{
"name": "upsert_memory_node",
"description": "Create or update a memory node with auto-generated TF-IDF embeddings.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"type": { "type": "string" },
"label": { "type": "string" },
"content": { "type": "string" },
"metadata": { "type": "object" }
},
"required": ["session_id", "type", "label", "content"]
}
},
{
"name": "create_relation",
"description": "Create a typed, weighted edge between two memory nodes.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"source_id": { "type": "string" },
"target_id": { "type": "string" },
"relation": {
"type": "string",
"enum": ["relates_to", "depends_on", "implements", "references", "similar_to", "contains"]
},
"weight": { "type": "number" },
"metadata": { "type": "object" }
},
"required": ["session_id", "source_id", "target_id", "relation"]
}
},
{
"name": "search_memory_graph",
"description": "Semantic search with graph traversal — returns direct matches and neighbor walk.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"query": { "type": "string" },
"max_depth": { "type": "integer" },
"top_k": { "type": "integer" },
"edge_filter": { "type": "string" }
},
"required": ["session_id", "query"]
}
},
{
"name": "prune_stale_links",
"description": "Remove decayed edges (e^(-λt) below threshold) and orphan nodes with low access count.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"threshold": { "type": "number" }
},
"required": ["session_id"]
}
},
{
"name": "add_interlinked_context",
"description": "Bulk-add nodes with auto-similarity linking (cosine >= 0.72 creates edges).",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": { "type": "string" },
"label": { "type": "string" },
"content": { "type": "string" },
"metadata": { "type": "object" }
},
"required": ["type", "label", "content"]
}
},
"auto_link": { "type": "boolean" }
},
"required": ["session_id", "items"]
}
},
{
"name": "retrieve_with_traversal",
"description": "Walk outward from a node, returning reachable neighbors scored by temporal decay and depth.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"start_node_id": { "type": "string" },
"max_depth": { "type": "integer" },
"edge_filter": { "type": "string" }
},
"required": ["session_id", "start_node_id"]
}
},
{
"name": "resolve_context",
"description": "Unified context lookup: short-term KV -> long-term graph -> miss. Returns source and score.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"key": { "type": "string" }
},
"required": ["session_id", "key"]
}
},
{
"name": "promote_to_long_term",
"description": "Promote a short-term KV entry to the long-term memory graph.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" },
"key": { "type": "string" },
"value": { "type": "string" },
"node_type": { "type": "string" },
"metadata": { "type": "object" }
},
"required": ["session_id", "key", "value"]
}
},
{
"name": "memory_status",
"description": "Unified view of short-term KV and long-term graph memory status for a session.",
"inputSchema": {
"type": "object",
"properties": {
"session_id": { "type": "string" }
},
"required": ["session_id"]
}
}
]
}
{
"mcpServers": {
"pmll-memory-mcp": {
"command": "docker",
"args": [
"run", "-i",
"-v", "pmll_data:/app/data",
"-e", "MEMORY_FILE_PATH=/app/data/memory.jsonl",
"--rm", "pmll-memory-mcp"
]
}
}
}
Add to .vscode/mcp.json (or open MCP: Open User Configuration from the Command Palette):
{
"servers": {
"pmll-memory-mcp": {
"command": "npx",
"args": ["-y", "pmll-memory-mcp"]
}
}
}
{
"servers": {
"pmll-memory-mcp": {
"command": "docker",
"args": [
"run", "-i",
"-v", "pmll_data:/app/data",
"-e", "MEMORY_FILE_PATH=/app/data/memory.jsonl",
"--rm", "pmll-memory-mcp"
]
}
}
}
# Build from the repository root
docker build -f mcp/Dockerfile -t pmll-memory-mcp .
# Run
docker run --rm -i pmll-memory-mcp:latest
# Run with persistent KV memory via volume
docker run --rm -i \
-v pmll_data:/app/data \
-e MEMORY_FILE_PATH=/app/data/memory.jsonl \
pmll-memory-mcp:latest
| Server / Integration | Directory / Source | Transport | Description |
|---|---|---|---|
| Unstoppable Domains | unstoppable-domains/ | HTTP (remote) | Search, purchase, and manage Web3 domain names via natural conversation. |
| Context+ | github.com/ForLoopCodes/contextplus | Integrated | Long-term semantic memory graph, adapted into memory-graph.ts and solution-engine.ts. By @ForLoopCodes. |
Full MCP server documentation: mcp/README.md
pmll-anchor)Memory / codework payloads stay off-chain. Optional 32-byte SHA-256 commitments are live on Stellar mainnet via Soroban pmll-anchor (shared with drQedwards/pmll).
ABI unchanged: init / store / get / bump only — do not invent fields or contract IDs.
This PPM tree may not include the full pmll-anchor/ contract sources; typed payload is still mirrored as skill.ts.
Invoke docs / contract source: pmll/SKILL.md. Local summary: SKILL.md.
| Network | Contract ID | Explorer |
|---|---|---|
| mainnet | CCF3B64AXLS4OLY5RN4H4K2CFZAYNZCJQY5MKCKCVAKMZNH7G7F7XUUF | stellar.expert |
| testnet | CDLQR24LLFWXTNGGJVJCRXAF3ZRDWFZRUFTDZ5SJOT2J33CS7DDYP7IU | stellar.expert |
Admin: GBFOFCD3XDANQWSGMHKJJ2V3YXS2QQD7RNC4LMDBVNBTUJOQZ3RLSB3E · wasm hash 1b6ad9c574e0f5c9e39968f836a410c03adcf057afa93a63d2710bd30fdd53ba
Skills summary: SKILL.md · full invoke docs: pmll/SKILL.md
┌───────────────┐
│ pypm (CLI) │ ← C-based command parser
└───────┬───────┘
│
▼
┌───────────────┐ ┌─────────────┐ ┌──────────────┐
│ Workspace │◀───▶│ Resolver │◀───▶│ Wheel Cache │
│ (TOML / YAML) │ │ (SAT + PEP) │ │ (~/.cache) │
└───────────────┘ └─────┬───────┘ └─────┬────────┘
│ │
▼ ▼
┌──────────┐ ┌────────────┐
│ Env Mgr │ │ Plugin Host│
│ (.venv) │ │ (dlopen) │
└──────────┘ └────────────┘
┌─────────────────────────────────────────────────────┐
│ pmll-memory-mcp v1.0.1 │
│ │
│ ┌──────────── Short-term (5 tools) ──────────┐ │
│ │ index.ts → peekContext() → kv-store.ts │ │
│ │ │ │ │
│ │ └──────► q-promise-bridge │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌──────── Long-term — Context+ (6 tools) ────┐ │
│ │ memory-graph.ts → embeddings.ts │ │
│ │ (nodes, edges, decay, cosine similarity) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌──────── Solution Engine (3 tools) ─────────┐ │
│ │ solution-engine.ts │ │
│ │ (resolve_context, promote, memory_status) │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
│ │
▼ ▼
PMLL.c / PMLL.h Q_promise_lib/
(memory_silo_t) (qpromise_* / libqpromise.so)
| File / Directory | Purpose |
|---|---|
Ppm.c | C-core CLI v0.0.3-dev — integrated single-file build (~500 LOC) |
Pypm.c | PyPM 0.3.x front-door dispatcher; delegates to module sources |
PMLL.c / PMLL.h | Associative/semantic silo, peek/peek_semantic, SAT bridge, init_pml=-1 |
SAT.c / SAT.h | Boolean SAT solver used for dependency resolution |
Q_promise_lib/ | Promise/continuation library (qpromise_*, libqpromise.so; single-threaded drain) |
skill.ts / SKILL.md | Off-chain CodeworkPayload + Stellar skills entry |
pmll-anchor/ | Soroban commitment contract (source on pmll; may be absent here) |
lattice/ | On pmll only — playable Stellar skills graph / ARC-AGI-3 play test |
mcp/ | TypeScript PMLL Memory MCP server (15 tools) |
mcp/src/memory-graph.ts | Long-term memory graph adapted from Context+ |
mcp/src/solution-engine.ts | Solution engine bridging short-term KV + long-term graph |
mcp/src/embeddings.ts | TF-IDF embeddings and cosine similarity for semantic search |
CLI/ | Extended CLI interface |
Panda-lib/ Torch-lib/ Numpy-lib/ | Library integration shims |
scripts/ | Build helpers and automation scripts |
slots + embeddings), peek + peek_semantic, SAT bridge, init_pml assignments start at -1 (undecided).qpromise_* + libqpromise.so; prototype QMemNode / q_mem_* API removed.skill.ts aligned for off-chain CodeworkPayload hashing into existing pmll-anchor (ABI unchanged).MCPServer with FastMCP fallback; Q-promise MCP demos load libqpromise.so.New & Improved
| Area | What's new |
|---|---|
| Unified source | v0.0.1 + v0.0.2 merged into a single pypm.c file to simplify builds. |
| Version bump | CLI now reports 0.0.3-dev. |
| Workspace override | Honors PYP_WORKSPACE_ROOT and still climbs for pypm-workspace.toml. |
| Doctor v2.1 | Counts issues and exits with that count; inline Python probe via here-doc. |
| Sandbox v2.1 | -d <DIR> flag; default remains mkdtemp. |
| Plugin fetcher hardening | Creates ~/.pypm/plugins safely; CURLOPT_FAILONERROR for HTTP 4xx/5xx; preserves plugin exit code. |
| Hermetic bundle flag | pypylock -o <file> works regardless of flag order; default dist/venv.tar.gz. |
| Error surfacing | fatal() now shows errno via perror; dlopen/curl errors bubble up. |
Fixes
getopt → optind = 2 before parsing.dlsym failed → now returns non-zero and closes handle.cwd for later getcwd() calls.Breaking changes
pypm version is now a sub-command (not --version flag).doctor exit codes can now be >1 (numeric issue count).Migration (0.0.2 → 0.0.3-dev)
| If you did … | Do this now |
|---|---|
./pypm doctor && echo OK | Check [[ $? -eq 0 ]] or parse the numeric count. |
Used pypm_v002.c / pypm_v001.c | Switch to pypm.c, make clean && make. |
Hard-coded dist/venv.tar.gz path | Pass -o flag for custom output paths. |
Known issues
LoadLibraryW, _mktemp_s, bsdtar.exe fallback (#22).pypylock relies on shell tar; libarchive port planned for 0.0.4.peek() pattern with TypeScript example, VS Code MCP configuration, and companion servers table from mcp/README.md.upsert_memory_node,
create_relation, search_memory_graph, prune_stale_links,
add_interlinked_context, retrieve_with_traversal.resolve_context, promote_to_long_term,
memory_status.graphql tool for flexible query/mutation access.init, peek, set, resolve, flush.PMLL.c::memory_silo_t.qpromise_* / libqpromise.so.mcp/unstoppable-domains/.Workspace autodetect, Doctor v2, Sandbox upgrade, Plugin add/run, pypylock -o.
Breaking: --version flag removed; doctor exits non-zero on issues.
Initial proof-of-concept — single-file CLI with doctor, sandbox, plugin, and pypylock.
| Version | Planned features |
|---|---|
| 0.0.4 | Lockfile parser + wheel copier for real hermetic bundles |
| 0.0.5 | libsolv-backed dependency resolver |
| 0.1.0 | Cross-platform shims (Windows / macOS) |
| 0.1.1 | WASI toolchain detection & wheel preference |
| future | SAT dependency solver, parallel wheel cache, workspaces, WASM resolution |
Pull requests are welcome! Open issues and PRs at
https://github.com/drQedwards/PPM/issues
If you find PPM or pmll-memory-mcp useful, please consider supporting development:
Built by Dr. Q Josef Kurk Edwards — making Python packaging fast, deterministic, and hackable, with a shared PMLL memory stack.