feature-map-cli 1.0.0__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/.gitignore +4 -0
  2. feature_map_cli-1.1.0/CHANGELOG.md +72 -0
  3. feature_map_cli-1.1.0/Formula/feature-map.rb +26 -0
  4. feature_map_cli-1.1.0/GUIDE.md +550 -0
  5. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/PKG-INFO +34 -13
  6. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/README.md +33 -12
  7. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/pyproject.toml +3 -1
  8. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/share/feature_map/skill/SKILL.md +4 -2
  9. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/share/feature_map/skill/references/authoring.md +3 -0
  10. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/share/feature_map/skill/references/commands.md +8 -2
  11. feature_map_cli-1.1.0/share/feature_map/skill/references/example-map.md +69 -0
  12. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/share/feature_map/skill/references/existing-repos.md +3 -2
  13. feature_map_cli-1.1.0/src/feature_map/_version.py +1 -0
  14. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/bootstrap.py +119 -32
  15. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/cli.py +51 -2
  16. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/init_cmd.py +9 -0
  17. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/install_cmd.py +24 -7
  18. feature_map_cli-1.1.0/src/feature_map/commands/update_cmd.py +389 -0
  19. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/config.py +4 -0
  20. feature_map_cli-1.1.0/src/feature_map/harness.py +100 -0
  21. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/paths.py +8 -0
  22. feature_map_cli-1.1.0/src/feature_map/prompt.py +99 -0
  23. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/helpers.py +7 -4
  24. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/test_bootstrap.py +107 -0
  25. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/test_cli.py +5 -2
  26. feature_map_cli-1.1.0/tests/test_harness.py +113 -0
  27. feature_map_cli-1.1.0/tests/test_npm_wrapper.py +31 -0
  28. feature_map_cli-1.1.0/tests/test_update.py +316 -0
  29. feature_map_cli-1.0.0/CHANGELOG.md +0 -37
  30. feature_map_cli-1.0.0/Formula/feature-map.rb +0 -31
  31. feature_map_cli-1.0.0/src/feature_map/_version.py +0 -1
  32. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/LICENSE +0 -0
  33. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/share/feature_map/schema/feature-map.schema.json +0 -0
  34. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/share/feature_map/templates/feature.yaml.tpl +0 -0
  35. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/__init__.py +0 -0
  36. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/__main__.py +0 -0
  37. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/__init__.py +0 -0
  38. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/check_cmd.py +0 -0
  39. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/find_cmd.py +0 -0
  40. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/graph_cmd.py +0 -0
  41. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/impact_cmd.py +0 -0
  42. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/list_cmd.py +0 -0
  43. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/search_cmd.py +0 -0
  44. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/show_cmd.py +0 -0
  45. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/stats_cmd.py +0 -0
  46. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/commands/validate_cmd.py +0 -0
  47. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/discover.py +0 -0
  48. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/errors.py +0 -0
  49. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/graph.py +0 -0
  50. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/loader.py +0 -0
  51. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/output.py +0 -0
  52. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/path_extract.py +0 -0
  53. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/path_normalize.py +0 -0
  54. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/path_resolve.py +0 -0
  55. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/text_index.py +0 -0
  56. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/src/feature_map/validate.py +0 -0
  57. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/fixtures/.features/auth.yaml +0 -0
  58. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/fixtures/.features/billing.yaml +0 -0
  59. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/fixtures/.features/notifications.yaml +0 -0
  60. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/fixtures/repo/src/app.py +0 -0
  61. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/fixtures/repo/src/auth/session.py +0 -0
  62. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/fixtures/repo/src/billing/plans.py +0 -0
  63. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/fixtures/repo/src/notify/send.py +0 -0
  64. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/test_paths.py +0 -0
  65. {feature_map_cli-1.0.0 → feature_map_cli-1.1.0}/tests/test_validate.py +0 -0
@@ -11,3 +11,7 @@ venv/
11
11
  .coverage
12
12
  htmlcov/
13
13
  .DS_Store
14
+ node_modules/
15
+ npm-debug.log*
16
+ *.tgz
17
+ .worktrees/
@@ -0,0 +1,72 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [1.1.0] — 2026-08-30
11
+
12
+ ### Added
13
+
14
+ - `feature-map update` upgrades the installed CLI (or reports that it is
15
+ already latest). Detects pip, npm, Homebrew, pipx, and uv from the
16
+ running executable and uses that package manager.
17
+ - `init` now mirrors the agent skill into every *known* harness skill directory
18
+ the repo already uses, alongside the unchanged primary target. Known set:
19
+ `.agents/skills`, `.claude/skills`, `.grok/skills`. A harness is mirrored only
20
+ when its config directory exists, so `init` never seeds an agent tree nobody
21
+ asked for, and no harness is privileged over another.
22
+ - `--skill-dir DIR` (repeatable) and `skill_dirs:` in `.feature-map.yaml` mirror
23
+ the skill into directories for harnesses the CLI does not know about. These
24
+ are always written.
25
+ - The `AGENTS.md` block now names the deployed skill by path, so an agent that
26
+ only reads `AGENTS.md` can find it without guessing.
27
+ - `references/example-map.md`: a complete feature map with the reasoning for
28
+ every line, plus the same feature written badly for contrast.
29
+ - `GUIDE.md` ships inside the package, so the skill's cross-references resolve
30
+ for pip/npm/brew installs. `install` reports its path (`--json` → `.guide`).
31
+ - `install` reports every known skill location (`--json` → `.skill_locations`).
32
+ - After bootstrapping, `feature-map init` offers to launch your agent harness
33
+ (`claude`, `cursor-agent`, `opencode`, `grok`, `codex`, `gemini`, `pi`) to
34
+ scour the repo and author the first maps, with an arrow-key picker when
35
+ multiple harnesses are on PATH. Shortcut with `-y/--yes` and
36
+ `-h/--harness <name>`; prompts are skipped for `--json` and non-TTY runs.
37
+ - npm package `feature-map-cli` (`npm install -g feature-map-cli`) wraps the
38
+ PyPI CLI in a local virtualenv. Still requires Python 3.8+.
39
+
40
+ ### Changed
41
+
42
+ - CLI `--help` describes the tool as a cross-app feature index for agents.
43
+
44
+ ## [1.0.0] — 2026-08-29
45
+
46
+ ### Added
47
+
48
+ - `feature-map` CLI
49
+ - Full command surface: `list`, `show`, `search`, `find`, `graph`, `validate`,
50
+ `check`, `impact`, `stats`, `init`, `install`, `--json`, `--version`
51
+ - `feature-map init` bootstraps any repo: `.features/`, agent skill, `.feature-map.yaml`,
52
+ `AGENTS.md` snippet, and `bin/feature-map` shim
53
+ - `feature-map init <name>` scaffolds a new map from the bundled template
54
+ - `feature-map init --upgrade-skill` refreshes the agent skill from the installed package
55
+ - Fixture-based test suite
56
+ - Homebrew formula in `Formula/feature-map.rb` (tap: `markschellhas/tap`)
57
+ - pip-installable entrypoint via `pyproject.toml` (`feature-map-cli`)
58
+
59
+ ### Changed
60
+
61
+ - Public CLI and Homebrew name is `feature-map` (`brew install markschellhas/tap/feature-map`).
62
+ The PyPI project is `feature-map-cli` (`pip install feature-map-cli`) because
63
+ PyPI treats `feature-map` as too similar to the existing biology package
64
+ `featuremap`. The Python import is `feature_map`.
65
+ - Repo-local `bin/feature-map` shim execs `feature-map` without recursing if
66
+ `bin/` is on PATH.
67
+ - `init` writes `<!-- feature-map:start -->` in `AGENTS.md` and migrates the
68
+ older `<!-- featuremap:start -->` block.
69
+
70
+ [Unreleased]: https://github.com/markschellhas/feature-map/compare/v1.1.0...HEAD
71
+ [1.1.0]: https://github.com/markschellhas/feature-map/releases/tag/v1.1.0
72
+ [1.0.0]: https://github.com/markschellhas/feature-map/releases/tag/v1.0.0
@@ -0,0 +1,26 @@
1
+ class FeatureMap < Formula
2
+ include Language::Python::Virtualenv
3
+
4
+ desc "Cross-app architecture research CLI"
5
+ homepage "https://github.com/markschellhas/feature-map"
6
+ url "https://files.pythonhosted.org/packages/1b/9b/4e4305e888854994e104e28da63d5d2d68dc40eb3b331ce37fa493c9fc65/feature_map_cli-1.0.0.tar.gz"
7
+ sha256 "fdb211503d71408f8aad68712666fdd0bdeab4676ab3f585935416fd69c7f7bc"
8
+ license "MIT"
9
+ head "https://github.com/markschellhas/feature-map.git", branch: "master"
10
+
11
+ depends_on "libyaml"
12
+ depends_on "python@3.12"
13
+
14
+ resource "pyyaml" do
15
+ url "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz"
16
+ sha256 "d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f"
17
+ end
18
+
19
+ def install
20
+ virtualenv_install_with_resources
21
+ end
22
+
23
+ test do
24
+ assert_match version.to_s, shell_output("#{bin}/feature-map --version")
25
+ end
26
+ end
@@ -0,0 +1,550 @@
1
+ # Feature Map — development, packaging, and adoption
2
+
3
+ This is the operator's guide for `feature-map`: how it was built, how to
4
+ publish it so anyone can install it, and how a developer (or an agent)
5
+ adopts it in another repository — including existing codebases that do
6
+ not yet have maps.
7
+
8
+ ---
9
+
10
+ ## Why this, not a wiki
11
+
12
+ A Karpathy-style (or any LLM-written) wiki works: agents dump what they
13
+ learned into markdown and the next session can read it. The failure mode
14
+ is **shape**. Language models write prose. A wiki page on "signup" becomes
15
+ a narrative — history, asides, duplicated README, a little architecture —
16
+ and the next agent has to **ingest the whole page** to find the three
17
+ files that matter. That is slow in wall time and expensive in tokens.
18
+
19
+ Feature Map stores the same knowledge as **fields**, not essays:
20
+
21
+ | Need | Wiki | Feature Map |
22
+ |------|------|-------------|
23
+ | What is this? | Buried in a paragraph | `purpose` |
24
+ | Where do I start? | Maybe a link, maybe not | `entry_points` (real paths) |
25
+ | Which apps? | Prose | `apps` |
26
+ | How does a user move? | A story | `user_flow` |
27
+ | What else is coupled? | "See also" if you are lucky | `related_features` → `graph` |
28
+ | Is this stale? | You re-read it | `check` (paths on disk), `validate` |
29
+
30
+ **How an agent finds a feature (cheap path):**
31
+
32
+ ```bash
33
+ feature-map list # names only
34
+ feature-map search billing # slugs + short snippets
35
+ feature-map show billing --section entry_points
36
+ ```
37
+
38
+ `list` is a few dozen tokens. `search` returns hits, not chapters.
39
+ `--section` loads **one key** from one YAML file. The agent opens the
40
+ code at those paths instead of reading a 2k-word wiki page and then
41
+ still grepping.
42
+
43
+ That is why it is more efficient:
44
+
45
+ 1. **Addressable.** The CLI is an index (`list`, `search`, `find`,
46
+ `impact`). A wiki is a pile of documents you `cat`.
47
+ 2. **Bounded reads.** Structured keys + `--section` cap context. A wiki
48
+ has no equivalent of "give me only the files."
49
+ 3. **Checkable.** `validate` and `check` catch missing fields and dead
50
+ paths. A wiki cannot tell you the controller it mentions was renamed.
51
+ 4. **Stable voice.** YAML fields do not grow a new introduction every
52
+ time an agent "updates the docs."
53
+
54
+ **Value to the developer** (human, not just the agent):
55
+
56
+ - You get a **directory of the product** — one slug per capability —
57
+ without maintaining a second documentation site.
58
+ - Reviews stay honest: if `entry_points` does not list the file you
59
+ changed, the map is wrong and you fix it in the same PR.
60
+ - Onboarding is `feature-map list` then `show`, not "read the wiki and"
61
+ hope the architecture section is current."
62
+ - You still write PRDs and plans for *what to build*. The map only
63
+ answers *where it lives and what it touches*. That split keeps both
64
+ artifacts small.
65
+
66
+ A wiki can still hold narrative (vision, history, runbooks). Feature Map
67
+ is the **index the agent is required to hit first** so it does not spend
68
+ the budget re-discovering the tree.
69
+
70
+ ---
71
+
72
+ ## 1. How we developed this
73
+
74
+ ### Why it exists
75
+
76
+ Taptics is a multi-app monorepo (`rails/`, `mobile_app/`, `worldcuppuzzles-web/`,
77
+ and others). Agents and engineers kept guessing which files belonged to which
78
+ product feature. The answer we wanted was a **per-repo, human-authored
79
+ architecture index** — YAML maps in `.features/` — plus a small CLI so agents
80
+ can `list` / `search` / `show` / `validate` instead of grepping the tree
81
+ blindly.
82
+
83
+ Maps are research infrastructure, not product features. They do not replace
84
+ PRDs or implementation plans. They tell you *where the code lives and how
85
+ the pieces connect* before you touch anything.
86
+
87
+ ### Two-phase delivery
88
+
89
+ The work is specified in playbook-app `docs/PRDs/prd-feature-map-cli.md`.
90
+
91
+ | Phase | Where | Goal |
92
+ |-------|--------|------|
93
+ | **1** | Inside playbook-app | Dogfood a complete CLI and agent skill against real maps |
94
+ | **2** | This `feature-map` package | Extract that CLI so other repos can install it |
95
+
96
+ Phase 1 shipped first under `.agents/skills/feature-map/` with a repo-root
97
+ `./bin/feature-map` shim. Commands, schema, discovery (walk up from `cwd` to
98
+ the git root), JSON output, and a bash harness were proven against the
99
+ monorepo's maps.
100
+
101
+ Phase 2 is this directory. The Python package was moved, not rewritten:
102
+
103
+ - Import package `feature_map`; public CLI / Homebrew name `feature-map`;
104
+ PyPI project `feature-map-cli`
105
+ - Assets (schema, template, agent skill) live in `share/feature_map/` and
106
+ ship inside the wheel
107
+ - Tests use `tests/fixtures/` only — no dependency on Taptics maps
108
+ - Defaults are generic (`apps: []`); Rails-style path fallbacks apply only
109
+ when `rails` is listed in `.feature-map.yaml`
110
+
111
+ ### Design rules that made extraction cheap
112
+
113
+ 1. **No imports from the host repo.** The CLI only reads `.features/`,
114
+ `.feature-map.yaml`, and the filesystem.
115
+ 2. **Package-relative assets.** Schema and templates resolve via
116
+ `feature_map.paths.assets_root()`, not hardcoded monorepo paths.
117
+ 3. **Thin entrypoint.** `python -m feature_map` and the `feature-map` console
118
+ script both call `feature_map.cli:main`.
119
+ 4. **Two meanings of `init`.** `feature-map init` bootstraps a consumer repo.
120
+ `feature-map init <name>` scaffolds one map. Both are required for
121
+ distribution: the first installs the workflow, the second authors data.
122
+
123
+ ### What a feature map is
124
+
125
+ A map is a YAML file `.features/<slug>.yaml` with at least:
126
+
127
+ - `feature_name` — matches the filename stem
128
+ - `purpose` — what it does and why
129
+ - `entry_points` — real file paths (and routes if useful)
130
+
131
+ Recommended: `apps`, `user_flow`, `related_features`, `notes`. Cross-app
132
+ features get one map, not one map per app. `related_features` is how
133
+ `graph` and `impact --transitive` work.
134
+
135
+ ### What we did *not* build
136
+
137
+ - No web UI or database of maps
138
+ - No auto-generator that invents maps from the AST (maps stay authored;
139
+ agents may draft them after reading the code — see §3)
140
+ - No coupling to Rails, Flutter, or Taptics runtime
141
+
142
+ ---
143
+
144
+ ## 2. How to package it so anybody can use it
145
+
146
+ The product that other people install is **this directory**, not playbook-app.
147
+ Map *data* never ships in the package. Each consumer repo keeps its own
148
+ `.features/*.yaml`.
149
+
150
+ ### 2.1 Split out of playbook-app (first publish)
151
+
152
+ This tree started as `playbook-app/featuremap/`. Cloud Agent tokens cannot
153
+ create GitHub repositories. Create `markschellhas/feature-map` (public, MIT)
154
+ in the GitHub UI, then:
155
+
156
+ ```bash
157
+ cd /path/to/playbook-app
158
+ git subtree split --prefix=featuremap -b featuremap-split
159
+ git push git@github.com:markschellhas/feature-map.git featuremap-split:main
160
+ ```
161
+
162
+ After that, develop and tag in the standalone repo. See `EXTRACT.md`.
163
+
164
+ ### 2.2 pip (primary for Linux / CI)
165
+
166
+ From the `feature-map` repo root:
167
+
168
+ ```bash
169
+ python3 -m pip install build twine
170
+ python3 -m build # sdist + wheel in dist/
171
+ python3 -m twine check dist/*
172
+ python3 -m twine upload dist/ # once PyPI project "feature-map-cli" exists
173
+ # Preferred: Trusted Publishing. Full steps: PUBLISH.md
174
+ ```
175
+
176
+ `pyproject.toml` already declares:
177
+
178
+ - distribution name `feature-map-cli`; import package `feature_map` under `src/feature_map`
179
+ - console script `feature-map = feature_map.cli:main`
180
+ - runtime dep `pyyaml>=6.0`
181
+ - wheel force-include of `share/feature_map` → `feature_map/share`
182
+
183
+ Until PyPI is live, anyone can install from git:
184
+
185
+ ```bash
186
+ pip install "git+https://github.com/markschellhas/feature-map.git"
187
+ # or a local checkout:
188
+ pip install -e /path/to/feature-map
189
+ ```
190
+
191
+ ### 2.3 Homebrew (primary for macOS)
192
+
193
+ `Formula/feature-map.rb` is a draft. After the GitHub repo exists
194
+ (full steps: `PUBLISH.md`):
195
+
196
+ 1. Tag a release: `git tag v1.0.0 && git push origin v1.0.0`
197
+ 2. Fill `url` + `sha256` on the formula (or keep `head` for `--HEAD`)
198
+ 3. Add the formula to a tap (`homebrew-taptics` or a personal tap)
199
+
200
+ ```bash
201
+ brew tap markschellhas/tap
202
+ brew install feature-map
203
+ # or during bring-up:
204
+ brew install --HEAD markschellhas/tap/feature-map
205
+ ```
206
+
207
+ The formula should leave `feature-map` on PATH and, when possible, install
208
+ `share/feature_map/{schema,templates,skill}` for `init`.
209
+
210
+ ### 2.4 Versioning
211
+
212
+ - Semver on the CLI (`feature-map --version`, today `1.1.0`)
213
+ - Skill frontmatter `version:` should match the CLI version
214
+ - Record changes in `CHANGELOG.md`
215
+ - Consumer repos may pin `min_cli_version` in `.feature-map.yaml`
216
+
217
+ ### 2.5 What a release contains vs what it does not
218
+
219
+ | Ships in the package | Stays in each consumer repo |
220
+ |----------------------|-----------------------------|
221
+ | `feature-map` binary | `.features/*.yaml` (the maps) |
222
+ | Schema + map template | `.feature-map.yaml` |
223
+ | Agent skill (`SKILL.md` + references) | `AGENTS.md` snippet (written by `init`) |
224
+ | Homebrew formula / CI for the tool | `bin/feature-map` shim (written by `init`) |
225
+
226
+ ### 2.6 Verify a package before you publish
227
+
228
+ ```bash
229
+ cd feature-map
230
+ pip install -e ".[dev]"
231
+ python -m pytest -q
232
+ feature-map --version
233
+ feature-map --help
234
+ ```
235
+
236
+ CI (`.github/workflows/ci.yml`) runs the same tests on 3.8 and 3.12.
237
+
238
+ ---
239
+
240
+ ## 3. Install and use it in another repository
241
+
242
+ This section is for a developer adopting Feature Map in **their** repo,
243
+ greenfield or existing. It is also the contract agents must follow once
244
+ `feature-map init` has run.
245
+
246
+ ### 3.1 Install the CLI
247
+
248
+ Pick one:
249
+
250
+ ```bash
251
+ # once published
252
+ brew install markschellhas/tap/feature-map
253
+ pip install feature-map-cli
254
+ npm install -g feature-map-cli
255
+
256
+ # until then
257
+ pip install "git+https://github.com/markschellhas/feature-map.git"
258
+ pip install -e /path/to/playbook-app/featuremap
259
+ ```
260
+
261
+ Confirm:
262
+
263
+ ```bash
264
+ feature-map --version
265
+ ```
266
+
267
+ ### 3.2 Bootstrap the repo
268
+
269
+ From the consumer repo root (must be a git checkout, or `init` still works
270
+ if you are already at the intended root):
271
+
272
+ ```bash
273
+ feature-map init
274
+ ```
275
+
276
+ This is idempotent. It:
277
+
278
+ 1. Creates `.features/`
279
+ 2. Copies the agent skill to `.agents/skills/feature-map/`
280
+ (or `.grok/skills/feature-map/` if that tree already exists), and
281
+ mirrors it into every other known harness directory the repo already
282
+ uses, plus any `--skill-dir` / `skill_dirs:` target
283
+ 3. Writes `.feature-map.yaml` if missing
284
+ 4. Appends (or refreshes) an `AGENTS.md` block that **requires** agents
285
+ to use Feature Map before feature work, and names the deployed skill
286
+ by path so an agent that only reads `AGENTS.md` can still find it
287
+ 5. Writes `bin/feature-map` — a shim that execs `feature-map` on PATH
288
+
289
+ Skill directories are harness-neutral. `.agents/skills/` stays the primary
290
+ target; a known harness is *additionally* mirrored only when the repo already
291
+ uses it (its config directory exists), so `init` never seeds an agent tree
292
+ nobody asked for. Known: `.agents/skills`, `.claude/skills`, `.grok/skills`.
293
+ For anything else, name it yourself — `--skill-dir .my-agent/skills`, or
294
+ `skill_dirs:` in `.feature-map.yaml` — and it is always written.
295
+
296
+ Useful flags: `--no-agents`, `--no-shim`, `--upgrade-skill`, `--force`,
297
+ `--skill-dir DIR` (repeatable).
298
+ Also: `-y/--yes` skips the "start authoring maps?" prompt and
299
+ `-h/--harness <name>` picks the agent harness non-interactively
300
+ (`claude|cursor-agent|opencode|grok|codex|gemini|pi`). On an empty repo
301
+ `init` then offers to launch your harness to scour the code and author the
302
+ first maps; answer `n` or pick `skip` to do it yourself.
303
+
304
+ Then declare this repo's apps so `check` can resolve paths:
305
+
306
+ ```yaml
307
+ # .feature-map.yaml
308
+ features_dir: .features
309
+ apps:
310
+ - api
311
+ - web
312
+ - mobile
313
+ required_sections:
314
+ - purpose
315
+ - entry_points
316
+ min_cli_version: "1.0.0"
317
+ # Extra skill mirror targets for harnesses this CLI does not know about:
318
+ # skill_dirs:
319
+ # - .my-agent/skills
320
+ ```
321
+
322
+ ### 3.3 Instruction for agents — always use the feature map
323
+
324
+ `feature-map init` writes this mandate into `AGENTS.md`. Keep it. Do not
325
+ weaken it. Downstream skills (plans, PRDs, debugging) should say:
326
+
327
+ > **REQUIRED SUB-SKILL:** Use `feature-map` before proceeding.
328
+
329
+ **Agents must:**
330
+
331
+ 1. **Before any feature work, debug, PRD, or plan** — run
332
+ `feature-map list` (or `./bin/feature-map list`).
333
+ 2. If the feature name is unclear — `feature-map search <keyword>` and
334
+ `feature-map find <path-fragment>`.
335
+ 3. Read the map — `feature-map <slug>` or
336
+ `feature-map show <slug> --section entry_points` to save tokens.
337
+ 4. For cross-cutting work — `feature-map graph <slug>`.
338
+ 5. After shipping architecture changes — update the relevant
339
+ `.features/*.yaml`, then `feature-map validate` and `feature-map check`.
340
+
341
+ **Agents must not** implement, plan, or "just grep the repo" when a map
342
+ exists for that area. The map is authoritative; the tree is how you
343
+ verify the map.
344
+
345
+ If `list` is empty, or search/find miss the area you are about to touch,
346
+ **stop and author maps first** (§3.4). Do not invent architecture in a
347
+ PRD or plan without writing the map.
348
+
349
+ Day-to-day commands:
350
+
351
+ ```bash
352
+ feature-map list
353
+ feature-map search billing
354
+ feature-map find src/invoices
355
+ feature-map billing
356
+ feature-map show billing --section entry_points
357
+ feature-map graph billing --format mermaid
358
+ feature-map validate
359
+ feature-map check
360
+ feature-map impact src/invoices/create.py
361
+ ```
362
+
363
+ `./bin/feature-map` is the same CLI if the global binary is not on PATH
364
+ in a given environment.
365
+
366
+ ### 3.4 Existing repos — scour the code, then write maps
367
+
368
+ `init` does **not** generate maps from source. On a repo that already has
369
+ code, an agent (or a developer) must **read the tree and author maps**.
370
+ This is expected and should be the first Feature Map task in that repo.
371
+
372
+ Do not emit one map per file. Cluster by *user-visible capability* or
373
+ *deployed subsystem*.
374
+
375
+ #### Step A — inventory the repo
376
+
377
+ ```bash
378
+ # top-level apps / packages
379
+ ls
380
+ # language / package manifests
381
+ # Gemfile, package.json, pyproject.toml, go.mod, pubspec.yaml, apps/, packages/
382
+ ```
383
+
384
+ Write the `apps:` list in `.feature-map.yaml` from that inventory
385
+ (`api`, `web`, `ios`, `worker`, …). Prefer directory names that `check`
386
+ can prefix onto paths.
387
+
388
+ #### Step B — find seams (where features show up)
389
+
390
+ Scour, in order, whatever exists:
391
+
392
+ | Signal | Typical paths |
393
+ |--------|----------------|
394
+ | HTTP routes | `config/routes.rb`, `**/routes.*`, OpenAPI, `app/controllers` |
395
+ | App shells | `src/App.svelte`, `lib/main.dart`, `cmd/*/main.go`, `app/page.tsx` |
396
+ | Domain models | `app/models`, `src/domain`, `internal/` |
397
+ | Background jobs | `app/jobs`, `workers/`, queues |
398
+ | CLIs | `bin/`, `cmd/`, `cli/` |
399
+ | Docs / PRDs | `docs/`, `README*`, existing architecture notes |
400
+ | Tests | test names often name the feature better than folders |
401
+
402
+ Use the CLI as you go:
403
+
404
+ ```bash
405
+ feature-map find <controller_or_package>
406
+ feature-map search <domain word>
407
+ ```
408
+
409
+ On a first pass those will miss (no maps yet). That is the signal to
410
+ **draft** maps, not to skip them.
411
+
412
+ #### Step C — cluster into features
413
+
414
+ A feature is a slice a human would name in a standup ("signup",
415
+ "billing", "push notifications"), usually spanning several files and
416
+ sometimes several apps.
417
+
418
+ Cluster when they share:
419
+
420
+ - the same user journey
421
+ - the same primary models / tables
422
+ - the same entry controllers or screens
423
+ - a documented product name
424
+
425
+ Split when journeys, owners, or deployables diverge. Cross-app flows
426
+ (one API + one mobile screen + one worker) are **one** map with multiple
427
+ `apps` and `entry_points`, not three maps.
428
+
429
+ #### Step D — author each map
430
+
431
+ ```bash
432
+ feature-map init signup # scaffold .features/signup.yaml
433
+ ```
434
+
435
+ Then replace placeholders by reading the real code. Required:
436
+
437
+ ```yaml
438
+ feature_name: signup
439
+ purpose: "How a new account is created and reaches the first authenticated screen."
440
+ entry_points:
441
+ - api/src/signup/handler.go
442
+ - web/src/routes/signup/+page.svelte
443
+ apps:
444
+ - api
445
+ - web
446
+ user_flow:
447
+ primary: "Email submit → API creates user → redirect to /app"
448
+ related_features:
449
+ - billing (plan attached after first login)
450
+ notes: >
451
+ Status: mapped from existing code on 2026-08-27. Confirm webhook path
452
+ before changing Stripe.
453
+ ```
454
+
455
+ Rules while scouring:
456
+
457
+ - Prefer **paths that exist on disk**. `feature-map check` will flag
458
+ missing ones; invented paths train agents to look in the wrong place.
459
+ - Routes (`GET /signup`) may appear in `entry_points` as extra context,
460
+ but put the implementing file next to them.
461
+ - `related_features` entries must start with a real slug once that map
462
+ exists (`billing (note)`, not a sentence).
463
+ - Record uncertainty in `notes` instead of guessing.
464
+
465
+ Work in batches: scaffold 5–10 obvious features, `validate`, then fill
466
+ gaps `check` and `stats` report.
467
+
468
+ ```bash
469
+ feature-map validate
470
+ feature-map check --json
471
+ feature-map stats --json
472
+ ```
473
+
474
+ `validate` without `--strict` treats missing recommended sections as
475
+ warnings (exit 0). Use `--strict` in CI once the first pass is honest.
476
+
477
+ #### Step E — when to stop the first pass
478
+
479
+ Stop when:
480
+
481
+ - Every app in `.feature-map.yaml` appears on at least one map
482
+ - The main user journeys (signup, core loop, billing/admin if any) have maps
483
+ - `feature-map search <product noun>` hits something for the nouns in the README
484
+ - `check` only reports paths you *intend* to add, not typos
485
+
486
+ You do not need 100% file coverage. You need **named doors** into the
487
+ system so the next agent does not start from zero.
488
+
489
+ #### Step F — keep maps alive
490
+
491
+ After that first scour:
492
+
493
+ - New feature → `feature-map init <slug>` in the same PR as the code
494
+ - Moved/renamed files → update `entry_points`, run `check`
495
+ - Cross-feature work → update `related_features` and re-read `graph`
496
+
497
+ ### 3.5 Greenfield repos
498
+
499
+ If there is almost no code yet, still `feature-map init`, then add a map
500
+ when the first vertical slice lands. Empty `.features/` plus the
501
+ `AGENTS.md` mandate is enough: the next agent is required to author the
502
+ map with the feature, not after the fact.
503
+
504
+ ### 3.6 CI in the consumer repo
505
+
506
+ ```yaml
507
+ # example GitHub Actions step
508
+ - run: pip install feature-map-cli
509
+ - run: feature-map validate
510
+ # optional, once maps are trusted:
511
+ # - run: feature-map validate --strict
512
+ ```
513
+
514
+ Trigger on changes to `.features/**` and, if you want a backstop, on
515
+ every PR.
516
+
517
+ ### 3.7 Upgrade
518
+
519
+ ```bash
520
+ feature-map update
521
+ # or, by hand:
522
+ # pip install -U feature-map-cli
523
+ # npm install -g feature-map-cli@latest
524
+ # brew upgrade markschellhas/tap/feature-map
525
+ feature-map init --upgrade-skill
526
+ ```
527
+
528
+ `feature-map update` detects whether this copy came from pip, npm, Homebrew,
529
+ pipx, or uv and upgrades through that channel. If you are already on the
530
+ latest version it says so and exits 0. A source/editable checkout cannot
531
+ be upgraded this way — install a released package instead.
532
+
533
+ `--upgrade-skill` overwrites the deployed `SKILL.md` and references from
534
+ the installed package version. Re-run `feature-map init` to refresh the
535
+ `AGENTS.md` marked block.
536
+
537
+ ---
538
+
539
+ ## Related files in this package
540
+
541
+ | File | Role |
542
+ |------|------|
543
+ | `README.md` | Short install + command list |
544
+ | `PUBLISH.md` | Submit to PyPI and Homebrew |
545
+ | `EXTRACT.md` | Split this directory into its own GitHub repo |
546
+ | `CHANGELOG.md` | Released CLI versions |
547
+ | `share/feature_map/skill/SKILL.md` | Agent skill copied by `init` |
548
+ | `share/feature_map/skill/references/existing-repos.md` | Scour-the-code playbook for agents |
549
+ | `share/feature_map/skill/references/authoring.md` | Map shape and conventions |
550
+ | `share/feature_map/skill/references/commands.md` | Full CLI reference |