Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion commands/test-way.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ Use the `way-match suggest` command:
Output is section-delimited (GAPS, COVERAGE, UNUSED, VOCABULARY). Parse and display in a readable format:

```
=== Vocabulary Analysis: softwaredev/security ===
=== Vocabulary Analysis: softwaredev/code/security ===

Gaps (body terms not in vocabulary, freq >= 2):
parameterized freq=3
Expand Down
4 changes: 2 additions & 2 deletions docs/governance.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ In an enterprise, policy documents and way implementations typically live in sep
```
compliance-repo/ your-claude-config/
├── docs/architecture/ ├── hooks/ways/
│ ├── ADR-150.md │ ├── softwaredev/commits/way.md
│ ├── ADR-150.md │ ├── softwaredev/delivery/commits/way.md
│ └── ADR-200.md │ │ (provenance: → ADR-150)
├── audit-ledger.json │ └── softwaredev/security/way.md
├── audit-ledger.json │ └── softwaredev/code/security/way.md
└── controls.xlsx └── governance/
├── policies/
└── provenance-manifest.json
Expand Down
12 changes: 6 additions & 6 deletions docs/hooks-and-ways.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,9 +368,9 @@ macro: append # macro output after static content
```

Macros generate dynamic content. Examples:
- `softwaredev/adr/macro.sh` - Tri-state detection: no tooling, tooling available, tooling installed
- `softwaredev/quality/macro.sh` - Scans for long files in the project, outputs priority list
- `softwaredev/github/macro.sh` - Detects solo vs team project, adjusts PR guidance
- `softwaredev/architecture/adr/macro.sh` - Tri-state detection: no tooling, tooling available, tooling installed
- `softwaredev/code/quality/macro.sh` - Scans for long files in the project, outputs priority list
- `softwaredev/delivery/github/macro.sh` - Detects solo vs team project, adjusts PR guidance

**Security**: Project-local macros only run if the project is listed in `~/.claude/trusted-project-macros`.

Expand All @@ -385,11 +385,11 @@ flowchart TD
classDef marker fill:#00695C,stroke:#004D40,color:#fff
classDef result fill:#2E7D32,stroke:#1B5E20,color:#fff

T["Trigger fires for softwaredev/github"] --> PL
T["Trigger fires for softwaredev/delivery/github"] --> PL

PL{"$PROJECT/.claude/ways/<br/>softwaredev/github/way.md<br/>exists?"}
PL{"$PROJECT/.claude/ways/<br/>softwaredev/delivery/github/way.md<br/>exists?"}
PL -->|yes| USE_P["Use project-local way"]:::project
PL -->|no| GL{"~/.claude/hooks/ways/<br/>softwaredev/github/way.md<br/>exists?"}:::global
PL -->|no| GL{"~/.claude/hooks/ways/<br/>softwaredev/delivery/github/way.md<br/>exists?"}:::global
GL -->|yes| USE_G["Use global way"]:::global
GL -->|no| SKIP["No output"]

Expand Down
2 changes: 1 addition & 1 deletion docs/hooks-and-ways/extending.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ These are discovered alongside global ways and follow the same matching rules.

A project-local way with the same domain/name path as a global way takes precedence. They share a single marker, so only the project-local version fires.

Example: If a project has `.claude/ways/softwaredev/testing/way.md`, it replaces `~/.claude/hooks/ways/softwaredev/testing/way.md` for that project.
Example: If a project has `.claude/ways/softwaredev/code/testing/way.md`, it replaces `~/.claude/hooks/ways/softwaredev/code/testing/way.md` for that project.

### Macros in project-local ways

Expand Down
4 changes: 2 additions & 2 deletions docs/hooks-and-ways/provenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,9 +131,9 @@ In an enterprise, policy documents and way implementations typically live in sep
```
compliance-repo/ your-claude-config/
├── docs/architecture/ ├── hooks/ways/
│ ├── ADR-150.md │ ├── softwaredev/commits/way.md
│ ├── ADR-150.md │ ├── softwaredev/delivery/commits/way.md
│ └── ADR-200.md │ │ (provenance: → ADR-150)
├── audit-ledger.json │ └── softwaredev/security/way.md
├── audit-ledger.json │ └── softwaredev/code/security/way.md
└── controls.xlsx └── provenance-manifest.json
```

Expand Down
6 changes: 3 additions & 3 deletions docs/hooks-and-ways/stats.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ You can't manage what you can't see. The ways system logs every firing event and
Every time a way fires, `log-event.sh` appends a line to `~/.claude/stats/events.jsonl`:

```json
{"ts":"2026-02-05T19:00:34Z","event":"way_fired","way":"softwaredev/commits","domain":"softwaredev","trigger":"bash","scope":"agent","project":"/home/you/myproject","session":"abc-123"}
{"ts":"2026-02-05T19:00:34Z","event":"way_fired","way":"softwaredev/delivery/commits","domain":"softwaredev","trigger":"bash","scope":"agent","project":"/home/you/myproject","session":"abc-123"}
```

Session start events are also logged. For teammates, the team name is included:
Expand Down Expand Up @@ -39,8 +39,8 @@ Top ways:
meta/todos 96 ████████████████████
meta/memory 96 ████████████████████
meta/knowledge 30 ██████
softwaredev/commits 19 ███
softwaredev/design 18 ███
softwaredev/delivery/commits 19 ███
softwaredev/architecture/design 18 ███

By scope:
agent 319
Expand Down
2 changes: 1 addition & 1 deletion docs/scripts/adr
4 changes: 2 additions & 2 deletions hooks/ways/check-bash-pre.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# │ keywords match │
# └─────────────────┘
#
# Ways are nested: domain/wayname/way.md (e.g., softwaredev/github/way.md)
# Ways are nested: domain/wayname/way.md (e.g., softwaredev/delivery/github/way.md)
# Multiple ways can match a single command - CONTEXT accumulates
# all matching way outputs. Markers prevent duplicate content.
# Output is returned as additionalContext JSON for Claude to see.
Expand All @@ -33,7 +33,7 @@ scan_ways() {

# Find all way.md files recursively
while IFS= read -r -d '' wayfile; do
# Extract way path relative to ways dir (e.g., "softwaredev/github")
# Extract way path relative to ways dir (e.g., "softwaredev/delivery/github")
waypath="${wayfile#$dir/}"
waypath="${waypath%/way.md}"

Expand Down
4 changes: 2 additions & 2 deletions hooks/ways/check-file-pre.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
# └───────────────────────┘ │ if files match │ └──────────────┘
# └─────────────────┘
#
# Ways are nested: domain/wayname/way.md (e.g., softwaredev/github/way.md)
# Ways are nested: domain/wayname/way.md (e.g., softwaredev/delivery/github/way.md)
# Multiple ways can match a single file path - CONTEXT accumulates
# all matching way outputs. Markers prevent duplicate content.
# Output is returned as additionalContext JSON for Claude to see.
Expand All @@ -31,7 +31,7 @@ scan_ways() {

# Find all way.md files recursively
while IFS= read -r -d '' wayfile; do
# Extract way path relative to ways dir (e.g., "softwaredev/github")
# Extract way path relative to ways dir (e.g., "softwaredev/delivery/github")
waypath="${wayfile#$dir/}"
waypath="${waypath%/way.md}"

Expand Down
4 changes: 2 additions & 2 deletions hooks/ways/check-prompt.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# │ semantic match │
# └─────────────────┘
#
# Ways are nested: domain/wayname/way.md (e.g., softwaredev/github/way.md)
# Ways are nested: domain/wayname/way.md (e.g., softwaredev/delivery/github/way.md)
# Matching is ADDITIVE: pattern (regex/keyword) and semantic are OR'd.
# Semantic matching degrades: BM25 binary → gzip NCD → skip.
# Project-local ways are scanned first (and take precedence).
Expand Down Expand Up @@ -45,7 +45,7 @@ scan_ways() {

# Find all way.md files recursively
while IFS= read -r -d '' wayfile; do
# Extract way path relative to ways dir (e.g., "softwaredev/github")
# Extract way path relative to ways dir (e.g., "softwaredev/delivery/github")
waypath="${wayfile#$dir/}"
waypath="${waypath%/way.md}"

Expand Down
2 changes: 1 addition & 1 deletion hooks/ways/log-event.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
# Log a ways event to ~/.claude/stats/events.jsonl
# Usage: log-event.sh key=value key=value ...
# Example: log-event.sh event=way_fired way=softwaredev/github trigger=prompt
# Example: log-event.sh event=way_fired way=softwaredev/delivery/github trigger=prompt
#
# All values are safely JSON-encoded via jq. Event log is append-only JSONL.

Expand Down
2 changes: 1 addition & 1 deletion hooks/ways/macro.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ CURRENT_DOMAIN=""

# Find all way.md files, sorted by path
while IFS= read -r wayfile; do
# Extract relative path (e.g., "softwaredev/github")
# Extract relative path (e.g., "softwaredev/delivery/github")
relpath="${wayfile#$WAYS_DIR/}"
relpath="${relpath%/way.md}"

Expand Down
4 changes: 2 additions & 2 deletions hooks/ways/show-way.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Show a "way" once per session (strips frontmatter, runs macro if configured)
# Usage: show-way.sh <way-path> <session-id>
#
# Way paths can be nested: "softwaredev/github", "awsops/iam", etc.
# Way paths can be nested: "softwaredev/delivery/github", "awsops/iam", etc.
# Looks for: {way-path}/way.md and optionally {way-path}/macro.sh
#
# STATE MACHINE:
Expand Down Expand Up @@ -34,7 +34,7 @@ TEAM=$(detect_team "$SESSION_ID")
# Check if domain is disabled via ~/.claude/ways.json
# Example: { "disabled": ["itops", "softwaredev"] }
WAYS_CONFIG="${HOME}/.claude/ways.json"
DOMAIN="${WAY%%/*}" # First path component (e.g., "softwaredev" from "softwaredev/github")
DOMAIN="${WAY%%/*}" # First path component (e.g., "softwaredev" from "softwaredev/delivery/github")
if [[ -f "$WAYS_CONFIG" ]]; then
if jq -e --arg d "$DOMAIN" '.disabled | index($d) != null' "$WAYS_CONFIG" >/dev/null 2>&1; then
exit 0
Expand Down
Loading