dotai-cli 0.6.0__tar.gz → 0.7.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 (84) hide show
  1. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/.gitignore +3 -0
  2. dotai_cli-0.7.0/CHANGELOG.md +65 -0
  3. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/PKG-INFO +43 -11
  4. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/README.md +41 -9
  5. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/pyproject.toml +1 -1
  6. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/__init__.py +1 -1
  7. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/agents.py +4 -0
  8. dotai_cli-0.7.0/src/dotai/catalog.py +67 -0
  9. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/agents_cmd.py +2 -1
  10. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/rules_cmd.py +8 -3
  11. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/sync_cmd.py +25 -26
  12. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/context.py +82 -61
  13. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/insights.py +17 -19
  14. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/maintenance.py +8 -6
  15. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/models.py +25 -8
  16. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/rules.py +5 -19
  17. dotai_cli-0.7.0/src/dotai/scope.py +91 -0
  18. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/skills.py +10 -11
  19. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/sync.py +27 -80
  20. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_agents.py +15 -0
  21. dotai_cli-0.7.0/tests/test_catalog.py +288 -0
  22. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_context.py +87 -3
  23. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_insights.py +22 -1
  24. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_skills.py +50 -0
  25. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_sync.py +19 -2
  26. dotai_cli-0.6.0/CHANGELOG.md +0 -34
  27. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/.github/workflows/ci.yml +0 -0
  28. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/.github/workflows/publish.yml +0 -0
  29. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/LICENSE +0 -0
  30. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/PRODUCT.md +0 -0
  31. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/rdc.yaml +0 -0
  32. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/__main__.py +0 -0
  33. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/__init__.py +0 -0
  34. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/__main__.py +0 -0
  35. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/insights_cmd.py +0 -0
  36. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/prefs_cmd.py +0 -0
  37. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/roles_cmd.py +0 -0
  38. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/cli/skills_cmd.py +0 -0
  39. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/converter.py +0 -0
  40. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/import_agent.py +0 -0
  41. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/preferences.py +0 -0
  42. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/roles.py +0 -0
  43. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/architect.md +0 -0
  44. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/debugger.md +0 -0
  45. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/founder.md +0 -0
  46. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/mentor.md +0 -0
  47. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/product-manager.md +0 -0
  48. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/qa.md +0 -0
  49. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/reviewer.md +0 -0
  50. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/security.md +0 -0
  51. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/ship.md +0 -0
  52. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/roles/writer.md +0 -0
  53. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/careful.md +0 -0
  54. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/commit-helper.md +0 -0
  55. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/compress.md +0 -0
  56. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/context-dump.md +0 -0
  57. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/investigate.md +0 -0
  58. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/learn.md +0 -0
  59. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/parallel-work.md +0 -0
  60. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/plan.md +0 -0
  61. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/review.md +0 -0
  62. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/scaffold.md +0 -0
  63. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/ship.md +0 -0
  64. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/techdebt.md +0 -0
  65. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/seed/skills/verify.md +0 -0
  66. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/store.py +0 -0
  67. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/tools/__init__.py +0 -0
  68. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/tools/base.py +0 -0
  69. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/tools/registry.py +0 -0
  70. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/utils.py +0 -0
  71. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/src/dotai/vet.py +0 -0
  72. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/__init__.py +0 -0
  73. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/conftest.py +0 -0
  74. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_converter.py +0 -0
  75. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_import_agent.py +0 -0
  76. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_maintenance.py +0 -0
  77. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_models.py +0 -0
  78. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_preferences.py +0 -0
  79. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_roles.py +0 -0
  80. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_rules.py +0 -0
  81. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_store.py +0 -0
  82. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_utils.py +0 -0
  83. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/tests/test_vet.py +0 -0
  84. {dotai_cli-0.6.0 → dotai_cli-0.7.0}/uv.lock +0 -0
@@ -14,3 +14,6 @@ CLAUDE.md
14
14
  AGENTS.md
15
15
  GEMINI.md
16
16
  .dotai-compression-proposal.json
17
+
18
+ # Local review sessions
19
+ .rdc/
@@ -0,0 +1,65 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.7.0 — 2026-11-04
6
+
7
+ ### Changed
8
+
9
+ - Share project discovery and override handling between context resolution and
10
+ primers, including nested directories, custom knowledge paths, and disabled
11
+ local overrides. Unrelated registered projects are excluded.
12
+ - Deliver full universal rule bodies and freeform conventions in resolved
13
+ context. Compact primers replace individual scoped-rule listings with a count
14
+ and resolver pointer.
15
+ - Load active general preferences by default, advertise other active domains,
16
+ and honor explicitly requested packs independently of domain selection.
17
+ - Preserve complete bodies when loading existing dotai skills while retaining
18
+ structured Python fields and identifying the source directory.
19
+ - Report file-scope facts separately from resolution status; missing files keep
20
+ a resolution provisional whenever scoped rules exist.
21
+
22
+ ### Fixed
23
+
24
+ - Match inherited rule globs from nested working directories and preserve hidden
25
+ and symlinked file names during matching.
26
+ - Avoid receipt temporary-file collisions and tolerate concurrent history
27
+ pruning at the retention limit.
28
+ - Pluralize the compact primer's file-scoped rule count.
29
+ - Treat a rule as universal only when every glob is a catch-all, so one
30
+ specific glob keeps the rule file-scoped.
31
+ - Search, `rules`, project audits, scoped insights, and project skill sync
32
+ read the same ancestor catalog as context. Unrelated projects stay out.
33
+
34
+ ## 0.6.0 — 2026-07-17
35
+
36
+ ### Added
37
+
38
+ - `dotai learn --directive` for proactive engineering standards, taste, and
39
+ guardrails without requiring a prior mistake.
40
+ - `dotai insights` for deterministic local delivery evidence: resolution health,
41
+ selection counts, last use, rule-summary exposure, and unused knowledge.
42
+ - Bounded metadata-only receipt history, retaining the latest 500 resolutions
43
+ per agent.
44
+ - `PRODUCT.md` defining dotai as portable engineering judgment for coding agents.
45
+
46
+ ### Changed
47
+
48
+ - Repositioned the CLI and documentation around developer-controlled engineering
49
+ judgment rather than universal context.
50
+ - `dotai sync` now has one repository-safe behavior: local context outside the
51
+ worktree.
52
+ - `dotai primer` now always emits the compact bootstrap.
53
+ - `dotai search` reads live knowledge instead of a cached index.
54
+ - `dotai install` is the single entry point for supported external skill formats.
55
+
56
+ ### Removed
57
+
58
+ - Commands: `watch`, `detach`, `index`, `tree`, `prompt`, `role`, `convert`, and
59
+ `import-plugin`.
60
+ - Shared/full/agent-specific sync controls and primer session overlays.
61
+ - Freeform `dotai learn --append-md` capture.
62
+ - The cached knowledge-tree model and `watchdog` dependency.
63
+
64
+ This release intentionally breaks pre-1.0 CLI compatibility to keep one clear,
65
+ local-first product path.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: dotai-cli
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Summary: Portable engineering judgment for coding agents
5
5
  Project-URL: Homepage, https://github.com/dawalama/dotai
6
6
  Project-URL: Repository, https://github.com/dawalama/dotai
@@ -150,7 +150,7 @@ dotai sync
150
150
 
151
151
  Local context storage does not, by itself, make an agent load the context. Until an agent adapter is configured, use `dotai primer --path .` to print a compact bootstrap for pasting or piping into your agent.
152
152
 
153
- dotai uses progressive disclosure to keep prompts small. Synced context contains rule summaries and role/skill catalogs. Expand only what a task needs:
153
+ dotai uses progressive disclosure to keep prompts small. Compact primers include complete universal directives, a count of file-scoped rules, and role/skill catalogs. Unrelated scoped rules are not listed individually. Expand what a task needs:
154
154
 
155
155
  ```bash
156
156
  # Expand rules matching the affected files
@@ -165,6 +165,26 @@ dotai context --path . --skill run_review
165
165
 
166
166
  Selection is deterministic: file globs, explicit context tags, active preference domains, and named skills or roles. dotai does not guess from semantic similarity. Every expanded item includes the reason it was selected.
167
167
 
168
+ `context` and `primer` share the same scoped catalog. Within a Git worktree,
169
+ dotai loads global knowledge and applicable ancestor knowledge directories down
170
+ to the invocation directory, honoring registered custom `ai_dir` paths. Outside
171
+ Git, discovery stops at the nearest registered project, or uses only the supplied
172
+ directory when it is unregistered. Unrelated registered projects are not read.
173
+ Local definitions override inherited items with the same ID; a disabled local
174
+ rule masks the inherited definition. A project's `disabled_rules` list excludes
175
+ global definitions while allowing explicit local replacements.
176
+
177
+ Affected files are relative to `--path` (absolute paths also work). Project rule
178
+ globs are relative to the directory owning that project's knowledge; global
179
+ globs use the repository or project root. Matching uses logical file paths,
180
+ including symlink names. The host remains responsible for filesystem permissions.
181
+
182
+ The resolver includes complete universal rule bodies and applicable `rules.md`
183
+ notes. Active `general` preference packs load by default. Other active domains
184
+ are listed without their bodies; select one with `--domain cli`, or load a named
185
+ pack directly with `--with-prefs <id>` regardless of its domain. Explicit packs
186
+ remain subject to scope and enabled state.
187
+
168
188
  ### Automatic delivery with Claude Code
169
189
 
170
190
  The resolver is infrastructure; you should not have to type `dotai context`
@@ -190,11 +210,11 @@ dotai context for substantial development work, after affected files are known,
190
210
  and to avoid repeated calls when the task has not changed. Repository and
191
211
  organization instructions remain authoritative.
192
212
 
193
- For file-sensitive workflows such as review, debugging, verification, scaffolding,
194
- maintenance, and release work, a resolution without `--files` is explicitly
213
+ When file-scoped rules exist, or a selected workflow requires files, a resolution without `--files` is explicitly
195
214
  marked provisional. Claude must resolve again after discovering the affected
196
215
  files. `dotai agent last claude` reports whether the latest resolution is
197
- `provisional` or `complete`.
216
+ `provisional` or `resolved`, and whether file scope was provided or remains
217
+ unknown. Supplied files do not prove that every affected file was discovered.
198
218
 
199
219
  The adapter does not modify repositories, install a persistent process, or use
200
220
  MCP. Existing personal Claude instructions are preserved. To remove only
@@ -225,7 +245,7 @@ dotai insights --json
225
245
  ```
226
246
 
227
247
  The report shows complete versus provisional resolutions, selection counts,
228
- last-selected timestamps, universal rule-summary exposure, and enabled items
248
+ last-selected timestamps, universal-rule exposure, and enabled items
229
249
  that have never been selected in the current window. Selection proves delivery,
230
250
  not compliance: dotai cannot claim that an agent followed an instruction merely
231
251
  because it received it.
@@ -448,6 +468,10 @@ Hard rules always take precedence if they conflict.
448
468
 
449
469
  ### Searching your knowledge
450
470
 
471
+ Search reads the same scoped catalog as `dotai context`. From a project, it
472
+ includes global knowledge and applicable ancestor directories, and it skips
473
+ unrelated registered projects. Pass `--path` to search another directory.
474
+
451
475
  ```bash
452
476
  # Search by keyword
453
477
  dotai search "useEffect"
@@ -590,9 +614,16 @@ Analyze the current branch's diff for issues that tests don't catch.
590
614
  4. Generate a structured report with file:line references
591
615
  ```
592
616
 
617
+ When loading existing dotai skill files, dotai preserves the complete Markdown
618
+ body for execution, including custom sections, nested steps, and code blocks.
619
+ Extracted fields remain available to Python consumers; rendering uses the
620
+ preserved body and identifies the source directory for relative resources.
621
+ Native-format import still uses the existing converter; migration to native
622
+ `SKILL.md` packages and preservation of host-specific metadata are separate work.
623
+
593
624
  ### Gotchas
594
625
 
595
- Skills should document **common failure points** — things that push the agent out of its normal way of thinking. Gotchas are rendered with warning markers in the agent prompt so they get extra attention.
626
+ Skills should document **common failure points** — things that push the agent out of its normal way of thinking. Gotchas in the Markdown body remain verbatim. Frontmatter gotchas and programmatically constructed gotcha fields are rendered with warning markers.
596
627
 
597
628
  ### Conditional Contexts
598
629
 
@@ -712,13 +743,14 @@ dotai toggle no-useeffect --off --project my-legacy-app
712
743
  dotai toggle no-useeffect --on
713
744
  ```
714
745
 
715
- Synced local context contains a compact bootstrap: universal rule summaries plus preference, role, and skill catalogs. Use `dotai context` to expand relevant material on demand.
746
+ Synced local context contains a compact bootstrap: full universal directives, a scoped-rule count, and preference, role, and skill catalogs. Use `dotai context` to expand relevant material on demand.
716
747
 
717
748
  ## Agent Sync
718
749
 
719
750
  `dotai sync` prepares repository-safe local context with:
720
751
 
721
- - **Universal structured rule summaries** (always visible)
752
+ - **Complete universal structured directives** (always visible)
753
+ - **A count and resolver pointer for file-scoped rules**
722
754
  - **Pointers to freeform `rules.md` conventions**
723
755
  - **Role and skill catalogs** (names, triggers, categories — not full workflows)
724
756
  Context is always written outside the worktree. Team instructions take precedence over personal dotai rules and preferences. dotai does not attempt unreliable keyword-based conflict resolution; the generated context tells the agent to ignore conflicting personal guidance and ask when a disagreement is ambiguous.
@@ -855,7 +887,7 @@ dotai install <source> [-s skill] # Install skills from git repo or local p
855
887
  dotai install --update [-s skill] [--skip-vet] # Vetted refresh from recorded sources
856
888
  dotai remove <skill> [-p project] # Remove an installed skill
857
889
  dotai new-skill <name> [-t trigger] # Create a new skill from template
858
- dotai search "query" [--type t] [--tag] # Search live knowledge
890
+ dotai search "query" [--type t] [--tag] [--path .] # Search knowledge for a directory
859
891
  ```
860
892
 
861
893
  ## Philosophy
@@ -122,7 +122,7 @@ dotai sync
122
122
 
123
123
  Local context storage does not, by itself, make an agent load the context. Until an agent adapter is configured, use `dotai primer --path .` to print a compact bootstrap for pasting or piping into your agent.
124
124
 
125
- dotai uses progressive disclosure to keep prompts small. Synced context contains rule summaries and role/skill catalogs. Expand only what a task needs:
125
+ dotai uses progressive disclosure to keep prompts small. Compact primers include complete universal directives, a count of file-scoped rules, and role/skill catalogs. Unrelated scoped rules are not listed individually. Expand what a task needs:
126
126
 
127
127
  ```bash
128
128
  # Expand rules matching the affected files
@@ -137,6 +137,26 @@ dotai context --path . --skill run_review
137
137
 
138
138
  Selection is deterministic: file globs, explicit context tags, active preference domains, and named skills or roles. dotai does not guess from semantic similarity. Every expanded item includes the reason it was selected.
139
139
 
140
+ `context` and `primer` share the same scoped catalog. Within a Git worktree,
141
+ dotai loads global knowledge and applicable ancestor knowledge directories down
142
+ to the invocation directory, honoring registered custom `ai_dir` paths. Outside
143
+ Git, discovery stops at the nearest registered project, or uses only the supplied
144
+ directory when it is unregistered. Unrelated registered projects are not read.
145
+ Local definitions override inherited items with the same ID; a disabled local
146
+ rule masks the inherited definition. A project's `disabled_rules` list excludes
147
+ global definitions while allowing explicit local replacements.
148
+
149
+ Affected files are relative to `--path` (absolute paths also work). Project rule
150
+ globs are relative to the directory owning that project's knowledge; global
151
+ globs use the repository or project root. Matching uses logical file paths,
152
+ including symlink names. The host remains responsible for filesystem permissions.
153
+
154
+ The resolver includes complete universal rule bodies and applicable `rules.md`
155
+ notes. Active `general` preference packs load by default. Other active domains
156
+ are listed without their bodies; select one with `--domain cli`, or load a named
157
+ pack directly with `--with-prefs <id>` regardless of its domain. Explicit packs
158
+ remain subject to scope and enabled state.
159
+
140
160
  ### Automatic delivery with Claude Code
141
161
 
142
162
  The resolver is infrastructure; you should not have to type `dotai context`
@@ -162,11 +182,11 @@ dotai context for substantial development work, after affected files are known,
162
182
  and to avoid repeated calls when the task has not changed. Repository and
163
183
  organization instructions remain authoritative.
164
184
 
165
- For file-sensitive workflows such as review, debugging, verification, scaffolding,
166
- maintenance, and release work, a resolution without `--files` is explicitly
185
+ When file-scoped rules exist, or a selected workflow requires files, a resolution without `--files` is explicitly
167
186
  marked provisional. Claude must resolve again after discovering the affected
168
187
  files. `dotai agent last claude` reports whether the latest resolution is
169
- `provisional` or `complete`.
188
+ `provisional` or `resolved`, and whether file scope was provided or remains
189
+ unknown. Supplied files do not prove that every affected file was discovered.
170
190
 
171
191
  The adapter does not modify repositories, install a persistent process, or use
172
192
  MCP. Existing personal Claude instructions are preserved. To remove only
@@ -197,7 +217,7 @@ dotai insights --json
197
217
  ```
198
218
 
199
219
  The report shows complete versus provisional resolutions, selection counts,
200
- last-selected timestamps, universal rule-summary exposure, and enabled items
220
+ last-selected timestamps, universal-rule exposure, and enabled items
201
221
  that have never been selected in the current window. Selection proves delivery,
202
222
  not compliance: dotai cannot claim that an agent followed an instruction merely
203
223
  because it received it.
@@ -420,6 +440,10 @@ Hard rules always take precedence if they conflict.
420
440
 
421
441
  ### Searching your knowledge
422
442
 
443
+ Search reads the same scoped catalog as `dotai context`. From a project, it
444
+ includes global knowledge and applicable ancestor directories, and it skips
445
+ unrelated registered projects. Pass `--path` to search another directory.
446
+
423
447
  ```bash
424
448
  # Search by keyword
425
449
  dotai search "useEffect"
@@ -562,9 +586,16 @@ Analyze the current branch's diff for issues that tests don't catch.
562
586
  4. Generate a structured report with file:line references
563
587
  ```
564
588
 
589
+ When loading existing dotai skill files, dotai preserves the complete Markdown
590
+ body for execution, including custom sections, nested steps, and code blocks.
591
+ Extracted fields remain available to Python consumers; rendering uses the
592
+ preserved body and identifies the source directory for relative resources.
593
+ Native-format import still uses the existing converter; migration to native
594
+ `SKILL.md` packages and preservation of host-specific metadata are separate work.
595
+
565
596
  ### Gotchas
566
597
 
567
- Skills should document **common failure points** — things that push the agent out of its normal way of thinking. Gotchas are rendered with warning markers in the agent prompt so they get extra attention.
598
+ Skills should document **common failure points** — things that push the agent out of its normal way of thinking. Gotchas in the Markdown body remain verbatim. Frontmatter gotchas and programmatically constructed gotcha fields are rendered with warning markers.
568
599
 
569
600
  ### Conditional Contexts
570
601
 
@@ -684,13 +715,14 @@ dotai toggle no-useeffect --off --project my-legacy-app
684
715
  dotai toggle no-useeffect --on
685
716
  ```
686
717
 
687
- Synced local context contains a compact bootstrap: universal rule summaries plus preference, role, and skill catalogs. Use `dotai context` to expand relevant material on demand.
718
+ Synced local context contains a compact bootstrap: full universal directives, a scoped-rule count, and preference, role, and skill catalogs. Use `dotai context` to expand relevant material on demand.
688
719
 
689
720
  ## Agent Sync
690
721
 
691
722
  `dotai sync` prepares repository-safe local context with:
692
723
 
693
- - **Universal structured rule summaries** (always visible)
724
+ - **Complete universal structured directives** (always visible)
725
+ - **A count and resolver pointer for file-scoped rules**
694
726
  - **Pointers to freeform `rules.md` conventions**
695
727
  - **Role and skill catalogs** (names, triggers, categories — not full workflows)
696
728
  Context is always written outside the worktree. Team instructions take precedence over personal dotai rules and preferences. dotai does not attempt unreliable keyword-based conflict resolution; the generated context tells the agent to ignore conflicting personal guidance and ask when a disagreement is ambiguous.
@@ -827,7 +859,7 @@ dotai install <source> [-s skill] # Install skills from git repo or local p
827
859
  dotai install --update [-s skill] [--skip-vet] # Vetted refresh from recorded sources
828
860
  dotai remove <skill> [-p project] # Remove an installed skill
829
861
  dotai new-skill <name> [-t trigger] # Create a new skill from template
830
- dotai search "query" [--type t] [--tag] # Search live knowledge
862
+ dotai search "query" [--type t] [--tag] [--path .] # Search knowledge for a directory
831
863
  ```
832
864
 
833
865
  ## Philosophy
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "dotai-cli"
7
- version = "0.6.0"
7
+ version = "0.7.0"
8
8
  description = "Portable engineering judgment for coding agents"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,3 +1,3 @@
1
1
  """dotai — Portable engineering judgment for coding agents."""
2
2
 
3
- __version__ = "0.6.0"
3
+ __version__ = "0.7.0"
@@ -30,6 +30,10 @@ resolution replaces the provisional one and loads file-scoped rules. Do not call
30
30
  dotai for casual conversation, simple factual questions, or repeatedly after a
31
31
  complete file-aware resolution unless the task or affected files materially change.
32
32
 
33
+ The result lists active preference domains that were not loaded. Add
34
+ `--domain <relevant domain>` when one applies, or `--with-prefs <id>` when the user
35
+ requests a specific pack. Active general preferences load by default.
36
+
33
37
  When the user explicitly invokes a dotai workflow such as `/run_review`, load it
34
38
  with `{command} context --agent claude --path . --skill run_review`. Treat dotai preferences as soft
35
39
  taste only; team rules, security constraints, and user instructions take precedence.
@@ -0,0 +1,67 @@
1
+ """One scoped view of knowledge for context resolution and exports."""
2
+
3
+ from dataclasses import dataclass
4
+ from pathlib import Path
5
+
6
+ from .models import GlobalConfig, PreferencePack, Role, Rule, Skill
7
+ from .preferences import load_active_pack_ids, load_preferences_from_dir
8
+ from .roles import load_roles_from_dir
9
+ from .rules import load_rules_from_dir, load_rules_md
10
+ from .scope import KnowledgeScope, resolve_scope
11
+ from .skills import load_skills_from_dir
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class FreeformNote:
16
+ scope: str
17
+ path: Path
18
+ body: str
19
+
20
+
21
+ @dataclass
22
+ class KnowledgeCatalog:
23
+ scope: KnowledgeScope
24
+ rules: list[Rule]
25
+ skills: list[Skill]
26
+ roles: list[Role]
27
+ preferences: list[PreferencePack]
28
+ notes: list[FreeformNote]
29
+ rule_roots: dict[str, Path | None]
30
+
31
+
32
+ def load_catalog(
33
+ config: GlobalConfig,
34
+ project_name: str | None = None,
35
+ project_path: Path | None = None,
36
+ extra_prefs: list[str] | None = None,
37
+ ) -> KnowledgeCatalog:
38
+ scope = resolve_scope(config, project_name, project_path)
39
+ rules: dict[str, Rule] = {}
40
+ skills: dict[str, Skill] = {}
41
+ roles: dict[str, Role] = {}
42
+ preferences: dict[str, PreferencePack] = {}
43
+ notes: list[FreeformNote] = []
44
+ rule_roots: dict[str, Path | None] = {}
45
+ for entry in scope.directories:
46
+ label, directory = entry.scope, entry.path
47
+ for rule in load_rules_from_dir(directory / "rules", label):
48
+ if directory != scope.directories[0].path or rule.id not in scope.disabled_rules:
49
+ rules[rule.id] = rule
50
+ rule_roots[rule.id] = entry.root_path
51
+ skills.update((s.id, s) for s in load_skills_from_dir(directory / "skills", label))
52
+ roles.update((r.id, r) for r in load_roles_from_dir(directory / "roles", label))
53
+ preferences.update((p.id, p) for p in load_preferences_from_dir(directory / "preferences", label))
54
+ body = load_rules_md(directory)
55
+ if body:
56
+ notes.append(FreeformNote(label, directory / "rules.md", body))
57
+
58
+ active = list(extra_prefs or [])
59
+ for entry in reversed(scope.directories):
60
+ active.extend(load_active_pack_ids(entry.path))
61
+ active = list(dict.fromkeys(active))
62
+ return KnowledgeCatalog(
63
+ scope, [r for r in rules.values() if r.enabled], list(skills.values()),
64
+ list(roles.values()),
65
+ [preferences[i] for i in active if i in preferences and preferences[i].enabled],
66
+ notes, rule_roots,
67
+ )
@@ -53,8 +53,9 @@ def agent(
53
53
  console.print(f" Project: {receipt.get('project_path', 'unknown')}")
54
54
  console.print(f" Task: {receipt.get('task') or 'not provided'}")
55
55
  provisional = bool(receipt.get("provisional"))
56
- console.print(f" Resolution: {'provisional' if provisional else 'complete'}")
56
+ console.print(f" Resolution: {'provisional' if provisional else 'resolved'}")
57
57
  files = receipt.get("files") or []
58
+ console.print(f" File scope: {'provided' if files else 'unknown'}")
58
59
  console.print(f" Files: {', '.join(files) if files else 'not known'}")
59
60
  console.print(f" Skill: {receipt.get('skill') or 'none'}")
60
61
  console.print(f" Role: {receipt.get('role') or 'none'}")
@@ -270,14 +270,19 @@ def rules(
270
270
  all: bool = typer.Option(False, "--all", "-a", help="Show all rules including disabled"),
271
271
  check: bool = typer.Option(False, "--check", help="Scan for duplicates, empty bodies, weak descriptions"),
272
272
  ):
273
- """List rules. Shows resolved active rules by default.
273
+ """List rules. Shows the active rules for this directory by default.
274
274
 
275
- Use --check to audit rule quality (duplicates, empty bodies).
275
+ Use --project to resolve a registered project, or --all for every rule in
276
+ the library. Use --check to audit rule quality (duplicates, empty bodies).
276
277
  """
278
+ from ..catalog import load_catalog
277
279
  from ..store import load_config
278
280
  from ..rules import load_all_rules, resolve_rules_for_project, check_rule_quality
279
281
 
280
282
  config = load_config()
283
+ if project and not config.get_project(project):
284
+ console.print(f"[red]Project '{project}' not found[/red]")
285
+ raise typer.Exit(2)
281
286
 
282
287
  if check:
283
288
  findings = check_rule_quality(config)
@@ -303,7 +308,7 @@ def rules(
303
308
  elif project:
304
309
  rule_list = resolve_rules_for_project(config, project)
305
310
  else:
306
- rule_list = load_all_rules(config)
311
+ rule_list = load_catalog(config, project_path=Path.cwd()).rules
307
312
 
308
313
  if not rule_list:
309
314
  console.print("[dim]No rules found. Use `dotai learn` to add rules.[/dim]")
@@ -22,10 +22,6 @@ def sync(
22
22
  config = load_config()
23
23
  project_path = Path(path).expanduser().resolve()
24
24
 
25
- # Find project name
26
- project_config = next((p for p in config.projects if p.path == project_path), None)
27
- project_name = project_config.name if project_config else None
28
-
29
25
  plan = plan_sync(project_path, get_config_dir())
30
26
 
31
27
  console.print(f"Mode: [bold]{plan.mode}[/bold]")
@@ -36,7 +32,7 @@ def sync(
36
32
  if check:
37
33
  return
38
34
 
39
- written = sync_local_context(plan, config, project_name)
35
+ written = sync_local_context(plan, config)
40
36
 
41
37
  for f in written:
42
38
  console.print(f" [green]Synced[/green] {f}")
@@ -53,14 +49,13 @@ def primer(
53
49
 
54
50
  config = load_config()
55
51
  project_path = Path(path).expanduser().resolve() if path else None
56
- if project_path:
57
- matched = next((p for p in config.projects if p.path == project_path), None)
58
- if matched:
59
- project = matched.name
60
- typer.echo(generate_primer(
61
- config, project, project_path=project_path,
62
- compact=True,
63
- ))
52
+ try:
53
+ typer.echo(generate_primer(
54
+ config, project, project_path=project_path, compact=True,
55
+ ))
56
+ except ValueError as error:
57
+ console.print(f"[red]{error}[/red]")
58
+ raise typer.Exit(2) from error
64
59
 
65
60
 
66
61
  @app.command("context")
@@ -88,13 +83,10 @@ def resolve_task_context(
88
83
 
89
84
  config = load_config()
90
85
  project_path = Path(path).expanduser().resolve()
91
- matched = next((p for p in config.projects if p.path == project_path), None)
92
- project_name = matched.name if matched else None
93
86
  try:
94
87
  resolved = resolve_context(
95
88
  config,
96
89
  project_path,
97
- project_name,
98
90
  task=task,
99
91
  files=split(files),
100
92
  contexts=split(contexts),
@@ -130,19 +122,21 @@ def search(
130
122
  query: str = typer.Argument("", help="Search keyword (optional if using --tag)"),
131
123
  type: Optional[str] = typer.Option(None, "--type", "-t", help="Filter by rule, preference, role, or skill"),
132
124
  tag: Optional[str] = typer.Option(None, "--tag", help="Filter by tag"),
125
+ path: str = typer.Option(".", "--path", help="Search the knowledge that applies to this directory"),
133
126
  ):
134
- """Search live dotai knowledge by keyword, type, or tag.
127
+ """Search the knowledge that applies to a directory.
128
+
129
+ Uses the same ancestor catalog as context and primer. Unrelated registered
130
+ projects are not read. Active preference packs are included; inactive packs
131
+ stay out.
135
132
 
136
133
  Examples:
137
134
  dotai search "useEffect"
138
135
  dotai search "review" --type skill
139
136
  dotai search --tag security
140
- dotai search "auth" --type rule --tag react
137
+ dotai search "auth" --type rule --tag react --path .
141
138
  """
142
- from ..preferences import load_all_preferences
143
- from ..roles import load_all_roles
144
- from ..rules import load_all_rules
145
- from ..skills import load_all_skills
139
+ from ..catalog import load_catalog
146
140
  from ..store import load_config
147
141
 
148
142
  valid_types = {"rule", "preference", "role", "skill"}
@@ -153,11 +147,16 @@ def search(
153
147
  raise typer.Exit(1)
154
148
 
155
149
  config = load_config()
150
+ try:
151
+ catalog = load_catalog(config, project_path=Path(path).expanduser().resolve())
152
+ except ValueError as error:
153
+ console.print(f"[red]{error}[/red]")
154
+ raise typer.Exit(2) from error
156
155
  items = []
157
- items.extend(("rule", item.id, item.description, item.tags, item.file_path) for item in load_all_rules(config))
158
- items.extend(("preference", item.id, item.description, item.tags, item.file_path) for item in load_all_preferences(config))
159
- items.extend(("role", item.id, item.description, item.tags, item.file_path) for item in load_all_roles(config))
160
- items.extend(("skill", item.id, item.description, item.tags, item.file_path) for item in load_all_skills(config))
156
+ items.extend(("rule", item.id, item.description, item.tags, item.file_path) for item in catalog.rules)
157
+ items.extend(("preference", item.id, item.description, item.tags, item.file_path) for item in catalog.preferences)
158
+ items.extend(("role", item.id, item.description, item.tags, item.file_path) for item in catalog.roles)
159
+ items.extend(("skill", item.id, item.description, item.tags, item.file_path) for item in catalog.skills)
161
160
 
162
161
  query_lower = query.strip().lower()
163
162
  tag_lower = tag.strip().lower() if tag else None