Skip to content
Touchskyer's Thinking Wall
S3E05
8 min read

Silicon Team S3E05: Turning a Personal Tool Into Something a Stranger Can Run

Silicon Team S3E05

EP01 told the story of one bug: skill.md and SKILL.md aren’t the same file on Linux. Fixed across 11 files. But that was just the tip of the iceberg.

#21 isn’t this episode’s subject — it’s the entry point. This episode expands from one filename into four categories of systemic problems that surface when a personal tool goes public: hardcoded paths, missing config layers, no session isolation, manual crash recovery. When you push a tool refined across two seasons on your own machine into the open, “doesn’t work” manifests in far more ways than capitalization.

Starting From #21

PR #21’s surface fix is git mv skill.md SKILL.md. But the rename itself is just the trigger — it exposed four categories of systemic problems.

Problem 1: Hardcoded Paths

OPC’s installation scripts and skill definitions had paths like this:

const MANAGED_ENTRIES = [
  'skill.md',
  'bin/',
  'pipeline/',
  'roles/',
  // ...
];

skill.md hardcoded in the array. package.json’s files field also hardcoded skill.md. The hook script opc-post-compact.sh had a recovery prompt referencing skill.md. Five pipeline documents mentioned “loading skill.md.”

One filename change, four layers of infrastructure to update. The essential problem with hardcoded paths isn’t “hard to change” — it’s “not knowing everywhere that references it.” There’s no single config file saying “this file is called X.” The name is scattered across code, configuration, scripts, and documentation — four independently maintained layers.

S2E08’s skill-audit found a similar issue: Logex’s skill.md hardcoded ~/Code/logex-data, but the actual directory was ~/Code/logex-projects/logex-data. Hardcoded paths are the chronic disease of personal tools — on your own machine, paths are always correct.

Fix direction: Centralize paths in a config file or environment variable. MANAGED_ENTRIES reads from a manifest.json; documentation generates references from the manifest. Renaming means changing one place.

Problem 2: Missing Config Layers

OPC’s configuration at the time had exactly one layer: defaults in the code.

const DEFAULT_MAX_LOOPS = 3;
const DEFAULT_FLOW = 'build-verify';

No user-level config file. No project-level config override. No environment variable override.

For one person, this is fine — I want to change a default, I change the code. But for external users, “change the code” is not a reasonable configuration method. If you want to change maxLoopsPerEdge from 3 to 5, you need to fork the repo, modify source code, and maintain your own branch.

Mature open-source tools typically have three to four config layers:

Code defaults → System config (~/.opc/config.yaml)
  → Project config (.opc/config.yaml)
  → Environment variables (OPC_MAX_LOOPS=5)
  → CLI arguments (--max-loops 5)

Each layer overrides the one above. Users never need to touch source code to adjust behavior.

Cherry Studio provides a reference: it uses Electron’s app.getPath('userData') for user config, supports GUI modification, persists to disk. Users never need to touch source code. VS Code takes it further — nearly all behavior is configurable through settings.json, from indentation width to Git auto-fetch intervals.

Fix direction: Introduce layered configuration. Code defaults → ~/.opc/config.yaml.opc/config.yaml → environment variables. Read with layer-by-layer overriding. Document each layer’s purpose.

Problem 3: Session Isolation

OPC’s session state lived in the .harness/ directory — project-level. This means:

  • Only one OPC pipeline can run per project at a time
  • If two terminal windows simultaneously run opc-harness init, the latter overwrites the former’s state
  • No mechanism to detect conflicts

For one person, you wouldn’t run two OPC instances simultaneously. But “wouldn’t” and “can’t” are different things. An external user could perfectly well run a full-stack flow in one terminal while running a quick review flow on the same project in another.

Fix direction: Session-level isolation. Each init creates a unique session directory (~/.opc/sessions/{project-hash}/{session-id}/), with a symlink pointing to latest. Multiple sessions coexist without interference. This solution was actually implemented — the plan file’s OPC execution protocol already uses session directories.

Problem 4: Crash Recovery

OPC’s context compaction would lose the current node position. S1 and S2’s approach: after each compaction, manually check .harness/flow-state.json, find currentNode, manually continue.

Manually. Every time.

For one person, you know what context compaction means, you know where to find the state. For an external user, the session suddenly gets shorter — then the tool stops — then they don’t know how to continue.

Fix direction: Automatic recovery after compaction. Hook script opc-post-compact.sh automatically reads flow-state.json after context compaction, injecting the current node and session path into the new context. This solution was also implemented — CLAUDE.md’s OPC Resume Protocol is this mechanism.

Common Root Cause

Hardcoded paths, missing config layers, no session isolation, manual crash recovery — these four problems look different on the surface but share the same root cause:

When developer equals user, many things don’t need explicit design.

Configuration? Changing code is configuration. Isolation? I only run one instance. Recovery? I know where to find the state file. Paths? Always correct on my machine.

These are all “will never break in my environment” assumptions. EP01 said “implicit environment assumptions are ticking time bombs.” This episode’s addendum: there isn’t just one bomb. It’s a minefield — you walk through safely because you know where the mines are. The first person who doesn’t know detonates one on their first step.

The Real Cost of Fixing

Problems dissected, now look at fixes. An honest estimate:

ProblemFix EffortChange Scope
Hardcoded pathsMediummanifest.json + all reference sites
Config layersHighNew config reading layer + docs + migration
Session isolationHighRewrite harness init/route/transition
Crash recoveryMediumHook scripts + state reading logic
Cross-platform compatHighCI matrix + Docker + tests

“High” means not a weekend project. Config layers require defining a format, writing a parser, handling override priority, and documenting each layer’s purpose. Session isolation requires rewriting core init and transition logic — that’s core code modification. Cross-platform compatibility requires setting up a CI matrix, running tests on Linux/macOS/Windows.

The distance from “I can run it” to “anyone can run it” isn’t fixing 11 files — it’s rewriting part of the infrastructure.

Usability Isn’t Polish — It’s the Foundation of Trust

EP01 defined the five-layer trust model. This episode addresses the first layer: infrastructure.

The infrastructure layer is the foundation of trust. No matter how sophisticated your review flow, how well-designed your role system, how rigorous your gate logic — if the first user’s npm install results in a non-working tool, the next four layers of trust don’t exist.

This is why “usability” isn’t the final step of product polish — it’s the first step of trust building.

S2 spent eight episodes optimizing review accuracy — adding roles, adding gates, adding design review, making processes visible. Then the first external user arrived and got stuck at filename capitalization.

What you thought the priority was: features → quality → usability. The real priority: usability → features → quality. Because the order users experience them is: can I install it → can I use it → is it good.

Industry References

This isn’t unique to OPC. Almost every open-source project that grew from a personal tool to a public project went through the same phase.

Node.js nvm (Node Version Manager): Originally a shell script assuming users run bash. Fish users discovered it didn’t work — needing an entirely separate nvm.fish implementation. Zsh users needed special configuration in .zshrc. Three shells, three compatibility solutions.

Docker’s early versions: Initially Linux-only. macOS and Windows users needed VMs. Docker for Mac/Windows took years to achieve a native experience. The distance from “works on Linux” to “works on any OS” was years of engineering investment.

Homebrew: Originally macOS-exclusive. Linuxbrew appeared as a port, taking years before being merged back into mainline as Homebrew on Linux. A package manager’s cross-platform journey involved far more environmental assumption cleanup than code volume would suggest.

The pattern is consistent: the creator’s development environment is the product’s implicit spec. When only the creator uses the product, this spec is invisible and zero-cost. When the first user who doesn’t share that environment appears, every implicit assumption becomes a bug.

If This Layer Isn’t Fixed, the Four Above It Are Suspended

Back to the five-layer trust model:

Layer 1  Infrastructure  ← This episode
Layer 2  Pattern         ← EP03 (role format self-explains)
Layer 3  Contribution    ← EP02 (five role PRs)
Layer 4  Core            ← EP04 (zero core PRs)
Layer 5  Resilience      ← Not there yet

The infrastructure layer is the foundation. Pattern understanding builds on “can run it.” Contribution builds on “understands the pattern.” Core trust builds on “successful contribution.” Resilience builds on “core understood and maintained by multiple people.”

Unstable foundation means every layer above is suspended in air. You can have the best review flow (layer 4), but if Linux users can’t install (layer 1), that flow doesn’t exist for them.

PR #21 is still OPEN. The other three problem categories analyzed in this episode are also still in progress. The infrastructure layer isn’t fully repaired yet.

Next episode pays S2’s biggest debt: the FAIL path was never triggered — does “no pass, no ship” actually have teeth?


Silicon Team S3: From “I Can Use It” to “Others Can Use It” ← S3E04: Nobody Touched the Gate — The Core Isn’t a Public Asset Yet | S3E06: Actually Verifying the FAIL Path for the First Time →

Comments