@forwardimpact/outpost 3.5.0 → 3.6.0
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.
- package/package.json +1 -1
- package/src/kb-manager.js +1 -1
- package/templates/.claude/skills/anarlog-process/SKILL.md +3 -3
- package/templates/.claude/skills/changelog/SKILL.md +136 -0
- package/templates/.claude/skills/deck-create/SKILL.md +40 -0
- package/templates/.claude/skills/deck-review/SKILL.md +156 -0
- package/templates/.claude/skills/deck-review/assets/slide-annotator.js +594 -0
- package/templates/.claude/skills/extract-entities/SKILL.md +3 -3
- package/templates/.claude/skills/{identify-user → person-identify}/SKILL.md +8 -7
- package/templates/.claude/skills/{identify-user → person-identify}/scripts/identify.sh +1 -1
- package/templates/.claude/skills/person-lookup/SKILL.md +97 -0
- package/templates/.claude/skills/person-lookup/scripts/lookup.sh +157 -0
- package/templates/.claude/skills/req-track/SKILL.md +3 -3
- package/templates/.claude/skills/req-workday/SKILL.md +2 -2
- package/templates/.claude/skills/upstream-instructions/SKILL.md +14 -23
- package/templates/CLAUDE.md +1 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: person-lookup
|
|
3
|
+
description: Look up ANY person in the corporate directory from free-text input (an email address, or a first / last / full name) and return their record — real name, title, department, company, email, employee ID, office, and manager. Searches the Global Catalog forest-wide via LDAP, authenticated with the existing Kerberos ticket. Use when the user asks "who is X", needs someone's title / department / manager / email, or wants to disambiguate a name. For the *current* user's own identity, use the sibling `person-identify` skill instead.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Person Lookup
|
|
7
|
+
|
|
8
|
+
Resolve **any** person in the corporate Active Directory from natural-language
|
|
9
|
+
input — an email, a login, or any part of a name. The sibling of
|
|
10
|
+
`person-identify`, but aimed at *other* people: it searches the **Global
|
|
11
|
+
Catalog** (forest-wide), handles multiple matches, flags external contacts and
|
|
12
|
+
vendor accounts, and — unlike `person-identify` — never writes the identity
|
|
13
|
+
cache. It's a read-only, throwaway lookup.
|
|
14
|
+
|
|
15
|
+
## Trigger
|
|
16
|
+
|
|
17
|
+
- The user asks "who is <name>", or for someone's title, department, manager,
|
|
18
|
+
email, or employee ID.
|
|
19
|
+
- A name is ambiguous and needs disambiguating against the directory.
|
|
20
|
+
- Another skill needs to resolve a person who is **not** the current user.
|
|
21
|
+
|
|
22
|
+
For the current user's own record (and to populate the identity cache that other
|
|
23
|
+
skills read), use `person-identify` instead.
|
|
24
|
+
|
|
25
|
+
## Prerequisites
|
|
26
|
+
|
|
27
|
+
- A valid **Kerberos ticket** (`klist` shows a principal). If absent:
|
|
28
|
+
`kinit <user>@<REALM>`.
|
|
29
|
+
- Network reachability to a domain controller (on-site or VPN).
|
|
30
|
+
- `ldapsearch` and `dig` — both ship with macOS; nothing to install.
|
|
31
|
+
|
|
32
|
+
Nothing is hardcoded: the realm and a domain controller are derived at runtime
|
|
33
|
+
from the ticket and DNS. The bind uses SASL/GSSAPI against the existing ticket —
|
|
34
|
+
no password is ever entered.
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bash .claude/skills/person-lookup/scripts/lookup.sh "Jane Doe"
|
|
40
|
+
bash .claude/skills/person-lookup/scripts/lookup.sh "jane.doe@example.com"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The argument is free text: an email, a full name, or just a surname.
|
|
44
|
+
|
|
45
|
+
## How it works
|
|
46
|
+
|
|
47
|
+
1. **Derive a domain controller** from the Kerberos principal's realm via DNS
|
|
48
|
+
SRV (same bootstrap as `person-identify`).
|
|
49
|
+
2. **Search the Global Catalog** (`ldap://$dc:3268`, base `""`). The GC spans
|
|
50
|
+
*every* domain in the forest, so a colleague in another region is found from
|
|
51
|
+
your own ticket — a plain domain-scoped search would miss them. It also
|
|
52
|
+
returns the common attributes (title, department, mail, manager), so one
|
|
53
|
+
query is enough.
|
|
54
|
+
3. **Match with ANR** (Ambiguous Name Resolution): the `(anr=<input>)` filter
|
|
55
|
+
matches an email, a login, or any name part in one shot. If ANR finds
|
|
56
|
+
nothing, fall back to a substring search on `mail` / `displayName` /
|
|
57
|
+
`proxyAddresses`.
|
|
58
|
+
4. **Resolve per match.** For a single hit, print the full record and resolve
|
|
59
|
+
the `manager` DN to a name. For several hits, print a compact
|
|
60
|
+
disambiguation list and suggest narrowing by email.
|
|
61
|
+
|
|
62
|
+
## Output
|
|
63
|
+
|
|
64
|
+
| Field | Source attribute |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| Name | `displayName` (fallback `cn`) |
|
|
67
|
+
| Type | `objectClass` + OU — **Employee**, **Contact (external)**, or **User (external / vendor)** |
|
|
68
|
+
| Email | `mail` |
|
|
69
|
+
| Title | `title` |
|
|
70
|
+
| Department | `department` |
|
|
71
|
+
| Company | `company` |
|
|
72
|
+
| Employee ID | `employeeID` |
|
|
73
|
+
| Phone / Office | `telephoneNumber` / `physicalDeliveryOfficeName` |
|
|
74
|
+
| Manager | `manager` (DN → resolved to a name) |
|
|
75
|
+
| DN | distinguished name (region + OU, useful for disambiguation) |
|
|
76
|
+
|
|
77
|
+
## Notes
|
|
78
|
+
|
|
79
|
+
- **Multiple matches are normal.** A common name, or a person who also has an
|
|
80
|
+
external **Contact** object (e.g. a vendor email alias), returns several
|
|
81
|
+
entries. The **Type** column distinguishes an internal **Employee** from an
|
|
82
|
+
external **Contact** (standard `objectClass=contact`). Some directories also
|
|
83
|
+
park external/vendor *user* accounts under a dedicated OU; set
|
|
84
|
+
`VENDOR_OU_PATTERN` at the top of `scripts/lookup.sh` to your directory's OU
|
|
85
|
+
substring (e.g. `OU=Contractors`) to flag those too. It is empty by default,
|
|
86
|
+
since the OU convention is organization-specific. Narrow with an email for an
|
|
87
|
+
exact hit.
|
|
88
|
+
- **Silent partial results.** Under load the directory occasionally returns an
|
|
89
|
+
entry's DN with no attributes (exit 0, no error). Every attribute fetch retries
|
|
90
|
+
with backoff, so a throttled response never masquerades as a person with a
|
|
91
|
+
blank title or email.
|
|
92
|
+
- **No cache.** This skill prints and exits. It never touches
|
|
93
|
+
`~/.cache/fit/outpost/state/identity.md` — that file is owned solely by
|
|
94
|
+
`person-identify`.
|
|
95
|
+
- **Ethics.** This reads objective, work-relevant directory data only, in line
|
|
96
|
+
with the knowledge base's integrity rules. It is not a tool for building
|
|
97
|
+
dossiers.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# person-lookup: resolve ANY person in the corporate directory from free-text
|
|
3
|
+
# input (an email address, or a first / last / full name) and print their
|
|
4
|
+
# directory record(s).
|
|
5
|
+
#
|
|
6
|
+
# Sibling to `person-identify`, but for *other* people, not the current user:
|
|
7
|
+
# - Searches the Global Catalog (port 3268, base "") so it reaches EVERY
|
|
8
|
+
# domain in the forest from a single ticket — colleagues in other regions
|
|
9
|
+
# are found, not just your own domain.
|
|
10
|
+
# - Uses Active Directory ANR (Ambiguous Name Resolution), so one filter
|
|
11
|
+
# matches an email, a login, or any part of a name.
|
|
12
|
+
# - Handles 0, 1, or many matches, and flags external Contacts / vendor
|
|
13
|
+
# accounts so an internal employee is never confused with an outside one.
|
|
14
|
+
# - NEVER writes the identity cache — this is a throwaway lookup.
|
|
15
|
+
#
|
|
16
|
+
# Auth uses SASL/GSSAPI against the existing Kerberos ticket — no password.
|
|
17
|
+
#
|
|
18
|
+
# Robustness note: under load the directory intermittently returns an entry's
|
|
19
|
+
# DN with NO attributes (exit 0, no error). Every attribute fetch below retries
|
|
20
|
+
# with backoff so a throttled response never looks like "this person has no
|
|
21
|
+
# title / email".
|
|
22
|
+
set -u
|
|
23
|
+
|
|
24
|
+
# Org-specific: substring of the DN's OU that marks external/vendor *user*
|
|
25
|
+
# accounts (external Contact objects are detected generically via objectClass).
|
|
26
|
+
# Empty by default — set it to your directory's convention, e.g. "OU=Contractors"
|
|
27
|
+
# or "OU=External", to label those accounts as "User (external / vendor)".
|
|
28
|
+
VENDOR_OU_PATTERN=""
|
|
29
|
+
|
|
30
|
+
QUERY="$*"
|
|
31
|
+
if [ -z "$QUERY" ]; then
|
|
32
|
+
echo "Usage: lookup.sh <email | name> e.g. lookup.sh \"Jane Doe\"" >&2
|
|
33
|
+
exit 2
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# 1. Derive the realm and a reachable domain controller from the Kerberos ticket.
|
|
37
|
+
princ=$(klist 2>/dev/null | sed -n 's/.*[Pp]rincipal: *//p' | head -1)
|
|
38
|
+
if [ -z "$princ" ]; then
|
|
39
|
+
echo "No Kerberos ticket found. Get one first, e.g.: kinit <user>@<REALM>" >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
realm=${princ#*@}
|
|
43
|
+
dom=$(printf '%s' "$realm" | tr '[:upper:]' '[:lower:]')
|
|
44
|
+
dc=$(dig +short SRV "_ldap._tcp.dc._msdcs.$dom" | awk 'NR==1{print $4}' | sed 's/\.$//')
|
|
45
|
+
[ -z "$dc" ] && dc=$(dig +short SRV "_ldap._tcp.$dom" | awk 'NR==1{print $4}' | sed 's/\.$//')
|
|
46
|
+
if [ -z "$dc" ]; then
|
|
47
|
+
echo "Could not find a domain controller for $dom via DNS SRV." >&2
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
# Global Catalog: forest-wide, base "" spans every domain.
|
|
52
|
+
GC="ldap://$dc:3268"
|
|
53
|
+
ATTRS="displayName givenName sn company title department employeeID mail telephoneNumber physicalDeliveryOfficeName objectClass manager"
|
|
54
|
+
MAX_SHOW=12 # cap detailed output for very broad name matches
|
|
55
|
+
|
|
56
|
+
# Pull one attribute out of an LDIF record (passed as $2), decoding base64 (::).
|
|
57
|
+
field() { # $1=attr $2=record
|
|
58
|
+
local attr="$1" line
|
|
59
|
+
line=$(printf '%s\n' "$2" | grep -m1 -E "^$attr:: ?|^$attr: ") || return 0
|
|
60
|
+
case "$line" in
|
|
61
|
+
"$attr:: "*) printf '%s' "${line#"$attr":: }" | base64 -D 2>/dev/null ;;
|
|
62
|
+
"$attr: "*) printf '%s' "${line#"$attr": }" ;;
|
|
63
|
+
esac
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
# List matching DNs for a filter (no attributes requested → reliable under load).
|
|
67
|
+
dns_for() { # $1=filter
|
|
68
|
+
ldapsearch -Y GSSAPI -LLL -o ldif-wrap=no -H "$GC" -b "" "$1" 1.1 2>/dev/null \
|
|
69
|
+
| sed -n 's/^dn: //p'
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# Fetch one entry's attributes by DN, retrying past the silent DN-only response.
|
|
73
|
+
fetch() { # $1=dn
|
|
74
|
+
local dn="$1" out tries=0
|
|
75
|
+
while [ "$tries" -lt 4 ]; do
|
|
76
|
+
out=$(ldapsearch -Y GSSAPI -LLL -o ldif-wrap=no -H "$GC" -b "$dn" -s base \
|
|
77
|
+
"(objectClass=*)" $ATTRS 2>/dev/null | grep -vE '^# ')
|
|
78
|
+
printf '%s\n' "$out" | grep -qE '^displayName:' && break
|
|
79
|
+
tries=$((tries + 1)); sleep "$tries"
|
|
80
|
+
done
|
|
81
|
+
printf '%s\n' "$out"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Resolve a manager (or any) DN to a display name.
|
|
85
|
+
name_of_dn() { # $1=dn
|
|
86
|
+
[ -z "$1" ] && return 0
|
|
87
|
+
field displayName "$(fetch "$1")"
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# Classify an entry: internal employee, external contact, or vendor account.
|
|
91
|
+
kind_of() { # $1=record $2=dn
|
|
92
|
+
local oc; oc=$(printf '%s\n' "$1" | grep -i '^objectClass:' | tr 'A-Z' 'a-z')
|
|
93
|
+
if printf '%s' "$oc" | grep -q 'contact'; then
|
|
94
|
+
echo "Contact (external)"
|
|
95
|
+
elif [ -n "$VENDOR_OU_PATTERN" ] && printf '%s' "$2" | grep -qiE ",$VENDOR_OU_PATTERN"; then
|
|
96
|
+
echo "User (external / vendor)"
|
|
97
|
+
else
|
|
98
|
+
echo "Employee"
|
|
99
|
+
fi
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# 2. Primary search (ANR), then a substring fallback if it finds nothing.
|
|
103
|
+
# (Portable array fill — macOS ships bash 3.2, which has no `mapfile`.)
|
|
104
|
+
read_dns() { # $1=filter -> populates global DNS array
|
|
105
|
+
DNS=()
|
|
106
|
+
local line
|
|
107
|
+
while IFS= read -r line; do
|
|
108
|
+
[ -n "$line" ] && DNS+=("$line")
|
|
109
|
+
done < <(dns_for "$1")
|
|
110
|
+
}
|
|
111
|
+
read_dns "(anr=$QUERY)"
|
|
112
|
+
if [ "${#DNS[@]}" -eq 0 ]; then
|
|
113
|
+
read_dns "(|(mail=*$QUERY*)(displayName=*$QUERY*)(proxyAddresses=*$QUERY*))"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
if [ "${#DNS[@]}" -eq 0 ]; then
|
|
117
|
+
echo "No directory match for: $QUERY"
|
|
118
|
+
exit 0
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
# 3a. Exactly one match → full record, with the manager resolved to a name.
|
|
122
|
+
if [ "${#DNS[@]}" -eq 1 ]; then
|
|
123
|
+
rec=$(fetch "${DNS[0]}")
|
|
124
|
+
mgr=$(name_of_dn "$(field manager "$rec")")
|
|
125
|
+
echo "# $(field displayName "$rec")"
|
|
126
|
+
echo
|
|
127
|
+
echo "- **Type:** $(kind_of "$rec" "${DNS[0]}")"
|
|
128
|
+
echo "- **Email:** $(field mail "$rec")"
|
|
129
|
+
echo "- **Title:** $(field title "$rec")"
|
|
130
|
+
echo "- **Department:** $(field department "$rec")"
|
|
131
|
+
echo "- **Company:** $(field company "$rec")"
|
|
132
|
+
echo "- **Employee ID:** $(field employeeID "$rec")"
|
|
133
|
+
echo "- **Phone:** $(field telephoneNumber "$rec")"
|
|
134
|
+
echo "- **Office:** $(field physicalDeliveryOfficeName "$rec")"
|
|
135
|
+
[ -n "$mgr" ] && echo "- **Manager:** $mgr"
|
|
136
|
+
echo "- **DN:** ${DNS[0]}"
|
|
137
|
+
exit 0
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
# 3b. Several matches → a compact disambiguation list (no per-row manager call).
|
|
141
|
+
echo "${#DNS[@]} matches for \"$QUERY\" — narrow with an email for an exact hit:"
|
|
142
|
+
echo
|
|
143
|
+
shown=0
|
|
144
|
+
for dn in "${DNS[@]}"; do
|
|
145
|
+
if [ "$shown" -ge "$MAX_SHOW" ]; then
|
|
146
|
+
echo
|
|
147
|
+
echo "_… and $(( ${#DNS[@]} - MAX_SHOW )) more. Refine the query._"
|
|
148
|
+
break
|
|
149
|
+
fi
|
|
150
|
+
rec=$(fetch "$dn")
|
|
151
|
+
name=$(field displayName "$rec"); [ -z "$name" ] && name=$(field cn "$rec")
|
|
152
|
+
printf -- '- **%s** — %s\n' "$name" "$(kind_of "$rec" "$dn")"
|
|
153
|
+
printf -- ' - %s · %s · %s\n' \
|
|
154
|
+
"$(field mail "$rec")" "$(field title "$rec")" "$(field department "$rec")"
|
|
155
|
+
printf -- ' - %s\n' "$dn"
|
|
156
|
+
shown=$((shown + 1))
|
|
157
|
+
done
|
|
@@ -20,7 +20,7 @@ pipeline from scattered email threads.
|
|
|
20
20
|
|
|
21
21
|
- Synced email data in `~/.cache/fit/outpost/apple_mail/` (from
|
|
22
22
|
`sync-apple-mail`).
|
|
23
|
-
- User identity — run the `identify
|
|
23
|
+
- User identity — run the `person-identify` skill to populate
|
|
24
24
|
`~/.cache/fit/outpost/state/identity.md`.
|
|
25
25
|
|
|
26
26
|
## Inputs
|
|
@@ -33,7 +33,7 @@ pipeline from scattered email threads.
|
|
|
33
33
|
- `~/.cache/fit/outpost/state/graph_processed` — processed-file index (shared
|
|
34
34
|
with `extract-entities`).
|
|
35
35
|
- `~/.cache/fit/outpost/state/identity.md` — user identity for self-exclusion
|
|
36
|
-
(written by the `identify
|
|
36
|
+
(written by the `person-identify` skill).
|
|
37
37
|
|
|
38
38
|
## Outputs
|
|
39
39
|
|
|
@@ -71,7 +71,7 @@ Process **10 files per run**.
|
|
|
71
71
|
### 1. Load context and pick the batch
|
|
72
72
|
|
|
73
73
|
Read the user's name, email, and domain from
|
|
74
|
-
`~/.cache/fit/outpost/state/identity.md` (run the `identify
|
|
74
|
+
`~/.cache/fit/outpost/state/identity.md` (run the `person-identify` skill first if
|
|
75
75
|
it is missing or stale). List new or changed source files:
|
|
76
76
|
|
|
77
77
|
```bash
|
|
@@ -27,7 +27,7 @@ integrate with the `req-track` pipeline format.
|
|
|
27
27
|
- A Workday requisition export accessible on the filesystem.
|
|
28
28
|
- `read-excel-file` package installed:
|
|
29
29
|
`bun pm ls read-excel-file 2>/dev/null || bun install read-excel-file`.
|
|
30
|
-
- User identity — run the `identify
|
|
30
|
+
- User identity — run the `person-identify` skill to populate
|
|
31
31
|
`~/.cache/fit/outpost/state/identity.md`.
|
|
32
32
|
|
|
33
33
|
## Inputs
|
|
@@ -66,7 +66,7 @@ Process **10 candidates per run**.
|
|
|
66
66
|
### 1. Set up
|
|
67
67
|
|
|
68
68
|
Read the user's identity from `~/.cache/fit/outpost/state/identity.md` (run the
|
|
69
|
-
`identify
|
|
69
|
+
`person-identify` skill first if it is missing or stale). Confirm the XLSX path.
|
|
70
70
|
Ensure the parser dependency is installed:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
@@ -24,15 +24,15 @@ monorepo. "Instructions" means all three surfaces, treated equally:
|
|
|
24
24
|
|
|
25
25
|
- A working Outpost installation with `CLAUDE.md`, `.claude/agents/`, and
|
|
26
26
|
`.claude/skills/`.
|
|
27
|
-
- Git available for change detection.
|
|
28
27
|
|
|
29
28
|
## Inputs
|
|
30
29
|
|
|
31
30
|
- `CLAUDE.md` — root installation instructions.
|
|
32
31
|
- `.claude/agents/*.md` — agent profiles.
|
|
33
32
|
- `.claude/skills/*/SKILL.md` and reference files — skills.
|
|
34
|
-
- `CHANGELOG.md` (root) — the existing changelog, for
|
|
35
|
-
-
|
|
33
|
+
- `CHANGELOG.md` (root) — the existing changelog, for what's already recorded.
|
|
34
|
+
- The changes made in the current working session — the source of truth for what
|
|
35
|
+
changed, since the KB lives on a synced filesystem and is not version-controlled.
|
|
36
36
|
|
|
37
37
|
## Outputs
|
|
38
38
|
|
|
@@ -49,8 +49,7 @@ monorepo. "Instructions" means all three surfaces, treated equally:
|
|
|
49
49
|
"updated CLAUDE.md" / "fixed stuff").
|
|
50
50
|
- [ ] New skills/agents include a brief description of their purpose; removed
|
|
51
51
|
ones explain why.
|
|
52
|
-
- [ ] Dates
|
|
53
|
-
uncommitted edits), not guessed.
|
|
52
|
+
- [ ] Dates are the date the change was made, not guessed.
|
|
54
53
|
- [ ] No duplicate entries for the same change.
|
|
55
54
|
|
|
56
55
|
</do_confirm_checklist>
|
|
@@ -65,18 +64,15 @@ head -20 CHANGELOG.md 2>/dev/null # newest date already recorded, if any
|
|
|
65
64
|
|
|
66
65
|
### 2. Identify changed instructions
|
|
67
66
|
|
|
68
|
-
|
|
67
|
+
Knowledge bases live on a synced filesystem, not in Git, so there is no commit
|
|
68
|
+
history to diff. Identify what changed from the work just done **this session**:
|
|
69
|
+
recall every edit, addition, removal, and rename made to `CLAUDE.md`,
|
|
70
|
+
`.claude/agents/`, and `.claude/skills/` during the current conversation, and
|
|
71
|
+
list them per surface.
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
CLAUDE.md '.claude/agents/' '.claude/skills/'
|
|
74
|
-
|
|
75
|
-
# Uncommitted working-tree changes (common in a live installation)
|
|
76
|
-
git status --short -- CLAUDE.md '.claude/agents/' '.claude/skills/'
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
If no `CHANGELOG.md` exists yet, consider all changes since the initial commit.
|
|
73
|
+
Use `CHANGELOG.md` only to see what's already recorded so you don't duplicate an
|
|
74
|
+
existing entry. If something was clearly changed but you can't reconstruct what
|
|
75
|
+
or why from the session, flag it as needing review rather than guessing.
|
|
80
76
|
|
|
81
77
|
### 3. Classify each change
|
|
82
78
|
|
|
@@ -95,13 +91,8 @@ If no `CHANGELOG.md` exists yet, consider all changes since the initial commit.
|
|
|
95
91
|
|
|
96
92
|
A single change often spans surfaces (e.g. a KB-structure change touching
|
|
97
93
|
`CLAUDE.md`, several agents, and several skills) — record it as **one entry**
|
|
98
|
-
whose Scope lists every surface touched.
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
git diff <commit> -- CLAUDE.md
|
|
102
|
-
git diff <commit> -- '.claude/agents/<agent>.md'
|
|
103
|
-
git diff <commit> -- '.claude/skills/<skill>/'
|
|
104
|
-
```
|
|
94
|
+
whose Scope lists every surface touched. Re-read the affected files to confirm
|
|
95
|
+
the change landed as intended before describing it.
|
|
105
96
|
|
|
106
97
|
### 4. Describe each change
|
|
107
98
|
|
package/templates/CLAUDE.md
CHANGED
|
@@ -113,7 +113,7 @@ knowledge-graph maintenance, recruitment, and communication.
|
|
|
113
113
|
|
|
114
114
|
The current user's identity is cached at
|
|
115
115
|
`~/.cache/fit/outpost/state/identity.md` — read it directly. If missing or stale,
|
|
116
|
-
run the `identify
|
|
116
|
+
run the `person-identify` skill to refresh it from the corporate directory.
|
|
117
117
|
|
|
118
118
|
## Working Outside This Directory
|
|
119
119
|
|