Keeps an AI-DLC project's own id map (US, AC, FR, NFR, BR, Q, U, C, E, ADR, R and the rest): /aidlc-ids:sync builds or brings it up to date without a model…

Every id an AI-DLC project's documents define (US1.1, AC1.1.2, FR1.4, NFR3, BR1.2, Q4, U31, C2, E7, ADR-009, R-01 and the rest) becomes, on the plugins' pages, a link with a tooltip saying what it is. This plugin keeps the map those pages read: for each id, its kind, its title, the start of its text and the document that defines it.
/aidlc-ids:sync build the map, or bring it up to date (only changed documents are read again)
/aidlc-ids:sync --force build it from scratch
The command runs without a model turn, so it costs no tokens. Agents run the same script before they build a page:
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/aidlc_ids.py" sync
The map is kept outside the project, in ~/.claude/plugins/data/aidlc-ids/maps/<checkout>/<space>--<intent>.json: one per checkout, as a worktree's branch may hold other documents. AIDLC_IDS_DIR moves the folder. Nothing of a project is in the plugin.
The plugins that draw pages (approval-gates, question-forms, story-points, review-findings) carry their own copy of the script, so they work without this plugin; the map they read and write is the same file. How a page uses it, and which of several definitions of an id it gets (every stage has its own Q1, every Unit its own BR1.1), is in shared/aidlc-ids/README.md.
claude plugin marketplace add maksymskuibida/mskuibida-ai-tools
claude plugin install aidlc-ids@mskuibida-tooling
python3 -m unittest scripts/tests/test_sync_shared.py
claude plugin test plugins/aidlc-idshooks/register.ts 34 lines1import type { EngineInterface, Register } from 'claude-code'
2
3// /aidlc-ids:sync builds or brings up to date the id map of the session's AI-DLC project, without a model turn: the
4// command runs scripts/aidlc_ids.py sync and answers with what it printed. Agents run the same script before they
5// build a page; the command is for the developer, and for a session that wants the map fresh without spending tokens.
6
7const COMMAND = 'sync'
8
9async function sync($: EngineInterface, args: string): Promise<string> {
10 const argv = ['python3', `${$.plugin.root}/scripts/aidlc_ids.py`, 'sync']
11 if (/(^|\s)--force(\s|$)/.test(args)) argv.push('--force')
12 const proc = $.process.spawn({ argv, cwd: await $.session.cwd() })
13 let out = ''
14 for await (const { text } of proc) out += text
15 const done = await proc.result
16
17 return done.code === 0 ? out.trim() : `The id map could not be synced: ${out.trim() || `exit ${done.code}`}`
18}
19
20export const register: Register = on => {
21 on('session.start', async ($, e, next) => {
22 await $.command.register({
23 name: COMMAND,
24 description: "Build or bring up to date this AI-DLC project's id map (US, AC, FR, NFR, BR, Q, U, ADR, ...)",
25 argumentHint: '[--force]',
26 immediate: true,
27 })
28
29 return next(e)
30 })
31
32 on('command.run', { command: COMMAND }, async ($, e) => ({ text: await sync($, e.args) }))
33}
34