{"slug": "before-your-side-projects-multiply-into-chaos-an-8-category-ledger-and-a-symlink", "title": "Before Your Side Projects Multiply Into Chaos: An 8-Category Ledger and a Symlink Tree", "summary": "A developer built an 8-category project ledger and symlink tree to manage over 40 side projects, including web apps, Chrome extensions, iOS apps, and AI tooling. The system uses a single `~/PROJECTS.md` file and symlinks under `~/Desktop/All-Projects/` to avoid moving real directories, preventing breakage of absolute path dependencies in tools like Vercel, launchd, and git worktrees. The developer also created a Claude Code skill to query the ledger for project state, monetization, and URLs.", "body_md": "This is part of my \"Claude Code environment\" series. Last time I wrote about [an autopilot that lets Claude Code improve itself autonomously and unattended](https://zenn.dev/bokuwalily/articles/claude-autopilot). But if the \"pile of automation scripts\" that showed up there isn't organized, you can't even decide what to hand the autopilot. So this time the topic is **the system I use to classify projects and manage where they live.**\n\nCounting the entries in my current ledger `~/PROJECTS.md`\n\n, there are **over 40** projects lined up — web apps, Chrome extensions, iOS apps, digital products, client work, AI tooling, PC automation, and OSS evaluations. Before things grew this far, I built a structure of \"8 categories + a ledger + a symlink tree.\" This article is about that design.\n\nClaude Code kept hunting for directories scattered across `~/dev/`\n\n, `~/Projects/`\n\n, `~/digital-products/`\n\n, and `~/oss-trial/`\n\nwith `find ~`\n\nevery single time. It wasn't just the search time — the **state (live/stalled/retired), the production URL, and whether it was monetized** were all scattered too, so every time I asked \"whatever happened to that app?\" I had to reconstruct the context from scratch.\n\nThe goal is to consolidate the ledger into a single file so I reach a state where \"ask, and the answer comes out immediately.\"\n\nHere's the definition table straight from `~/PROJECTS.md`\n\n.\n\n| Code | Definition |\n|---|---|\n`01-webapp` |\nWeb apps / web games that are deployed and used |\n`02-chrome-ext` |\nChrome extensions (MV3) + their dedicated backend API |\n`03-ios-app` |\niOS native / delivery wrappers |\n`04-digital-product` |\nnote monetization, digital products, content for sale |\n`05-client-work` |\nContract / commissioned work / company repos (third-party owner remote = push with care) |\n`06-claude-tooling` |\nInfrastructure, skills, and integrations that act on Claude / the AI agent itself |\n`07-pc-automation` |\nPC automation, scrapers, CLI scripts |\n`08-oss-eval` |\nEvaluation, experimentation, and sandboxing of external OSS |\n\nAdding categories dilutes their meaning, so I only create a new one \"when something genuinely fits none of the eight.\"\n\nThe decision is made by **how it's delivered, not by its name.** For example, `autolike-license-server`\n\nsounds like an API name, but it's a backend dedicated to license verification for a Chrome extension, so it goes under `02-chrome-ext`\n\n. Judging by name would misclassify it as \"API → server → `01-webapp`\n\n.\"\n\nIt's tempting to think \"organizing = moving folders,\" but in side-project development, **dependencies on absolute paths hide in three places.**\n\n`.vercel/project.json`\n\n`vercel deploy`\n\npoints at a different project.`ProgramArguments`\n\nis registered as the real path. Move it, and the cron job dies.`git worktree add`\n\nholds the real path in `.git/worktrees/<name>/gitdir`\n\n.⚠️ Physically moving a real directory is strictly forbidden.\n\n`.vercel`\n\n, launchd plists, and git worktrees break because they depend on absolute paths. \"Classification\" is expressed with symlinks + the ledger.\n\nYou never touch the real directory — you just **create a symlink under ~/Desktop/All-Projects/<category>/.**\n\n```\n# Classify a new project (without moving the real directory)\nln -sfn ~/dev/takugumi ~/Desktop/All-Projects/01-webapp/\n\n# Verify\nls ~/Desktop/All-Projects/01-webapp/\n# Shows something like  takugumi -> ~/dev/takugumi\n```\n\nIn `ln -sfn`\n\n, the `-f`\n\noverwrites an existing symlink, and `-n`\n\nprevents it from burrowing into the target when the target is a directory. Without these two flags you get a double-nested link.\n\nThe ledger `~/PROJECTS.md`\n\nis one line per project, holding the path, state, monetization, production URL, and cautions (currently 8 categories × over 40 projects total). By reading this one file, Claude Code can instantly answer \"Where's the iOS app for the job-hunt tracker?\" or \"Which ones are in a live state?\"\n\nThe procedure is written in `~/.claude/skills/auto/project-categorization/SKILL.md`\n\n, and it fires automatically every time a new project is created. The heart of the procedure is only this:\n\n```\nWhen starting a new project, before you begin writing code:\n\n1. Decide what you're building → pick one of the 8 categories above\n   (Decide by how it's delivered — not by name or first impression)\n2. Only if it fits none of the existing 8, create a new 09-<kebab>\n3. Create the real directory under the appropriate parent dir\n   Web app / extension → ~/dev or ~/Projects\n   Product → ~/digital-products\n   OSS evaluation → ~/oss-trial\n4. ln -sfn <real path> ~/Desktop/All-Projects/<category>/\n5. Add a row to the relevant category table in ~/PROJECTS.md\n```\n\nBecause CLAUDE.md also says \"when creating a new project, always classify it into one of the 8 categories before starting,\" Claude begins with classification without being told.\n\n```\n# Check that the symlink was created correctly\nls ~/Desktop/All-Projects/01-webapp/\n\n# Check that it was appended to the ledger\ngrep \"takugumi\" ~/PROJECTS.md\n\n# For client-work: check that secrets are ignored\ngit -C ~/dev/<project> check-ignore credentials.json\n```\n\nDrawn from what I collected in the auto-skill's `Pitfalls`\n\nsection.\n\n`autolike-license-server`\n\n(a Chrome extension backend) under \"server = `01-webapp`\n\n.\" Read `package.json`\n\nor the README and judge by how it's delivered.`05-client-work`\n\n`toc-seo/credentials.json`\n\n(a GCP key) was sitting bare in the root of a company repo. Every time you create client-work, check that secret-key patterns are in `.gitignore`\n\n.`ababa-pr/*`\n\nand `fujibee/*`\n\nare treated as `05-client-work`\n\nand pushing is forbidden. Check the owner with `git remote -v`\n\nbefore pushing.`~/PROJECTS.md`\n\n+ the `~/Desktop/All-Projects/<category>/`\n\nsymlink tree is the source of truthNext time, I'll write about the setup that **auto-generates a Mermaid diagram of these organized projects every morning and drops it on the Desktop.**\n\n*Written by **Lily** — I ship iOS apps and automate my content stack with Claude Code.\n\nFollow along: [Portfolio](https://bokuwalily.com) · [X](https://x.com/bokuwalily) · [GitHub](https://github.com/bokuwalily)*", "url": "https://wpnews.pro/news/before-your-side-projects-multiply-into-chaos-an-8-category-ledger-and-a-symlink", "canonical_source": "https://dev.to/bokuwalily/before-your-side-projects-multiply-into-chaos-an-8-category-ledger-and-a-symlink-tree-bi2", "published_at": "2026-07-14 05:00:05+00:00", "updated_at": "2026-07-14 05:30:22.733296+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-tools"], "entities": ["Claude Code", "Vercel", "launchd", "git"], "alternates": {"html": "https://wpnews.pro/news/before-your-side-projects-multiply-into-chaos-an-8-category-ledger-and-a-symlink", "markdown": "https://wpnews.pro/news/before-your-side-projects-multiply-into-chaos-an-8-category-ledger-and-a-symlink.md", "text": "https://wpnews.pro/news/before-your-side-projects-multiply-into-chaos-an-8-category-ledger-and-a-symlink.txt", "jsonld": "https://wpnews.pro/news/before-your-side-projects-multiply-into-chaos-an-8-category-ledger-and-a-symlink.jsonld"}}