nemo-cli 0.0.1__tar.gz → 0.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 (114) hide show
  1. nemo_cli-0.1.0/.claude/skills/close-session/SKILL.md +37 -0
  2. nemo_cli-0.1.0/.claude/skills/issue-new/SKILL.md +63 -0
  3. nemo_cli-0.1.0/.claude/skills/issue-start/SKILL.md +39 -0
  4. nemo_cli-0.1.0/.claude/skills/review-pr/SKILL.md +115 -0
  5. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.claude/skills/start-session/SKILL.md +14 -0
  6. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.claude/skills/validate-context/SKILL.md +10 -2
  7. nemo_cli-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
  8. nemo_cli-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  9. nemo_cli-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +23 -0
  10. nemo_cli-0.1.0/.github/ISSUE_TEMPLATE/work-unit.md +44 -0
  11. nemo_cli-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +43 -0
  12. nemo_cli-0.1.0/.github/workflows/ci.yml +170 -0
  13. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.github/workflows/publish.yml +5 -5
  14. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/CHANGELOG.md +41 -1
  15. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/CLAUDE.md +36 -22
  16. nemo_cli-0.1.0/CONTRIBUTING.md +47 -0
  17. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/PKG-INFO +50 -42
  18. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/README.md +48 -40
  19. nemo_cli-0.1.0/SECURITY.md +50 -0
  20. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/ARCHITECTURE.md +25 -17
  21. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/CONVENTIONS.md +49 -14
  22. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/STACK.md +7 -6
  23. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/005-github-flow-branching.md +5 -3
  24. nemo_cli-0.1.0/docs/decisions/013-adr-before-implementing.md +60 -0
  25. nemo_cli-0.1.0/docs/decisions/014-english-as-context-language.md +54 -0
  26. nemo_cli-0.1.0/docs/decisions/015-skills-over-slash-commands.md +59 -0
  27. nemo_cli-0.1.0/docs/decisions/016-document-corrections-not-fixes.md +52 -0
  28. nemo_cli-0.1.0/docs/decisions/017-atomic-task-instructions.md +58 -0
  29. nemo_cli-0.1.0/docs/decisions/018-session-close-ritual.md +59 -0
  30. nemo_cli-0.1.0/docs/decisions/019-short-sessions-over-long.md +59 -0
  31. nemo_cli-0.1.0/docs/decisions/020-pr-review-against-context.md +63 -0
  32. nemo_cli-0.1.0/docs/decisions/021-work-units-external-tracker.md +75 -0
  33. nemo_cli-0.1.0/docs/decisions/022-no-ai-attribution.md +55 -0
  34. nemo_cli-0.1.0/docs/decisions/023-continuous-integration.md +62 -0
  35. nemo_cli-0.1.0/docs/decisions/024-repository-governance.md +64 -0
  36. nemo_cli-0.1.0/docs/decisions/025-interactive-login.md +85 -0
  37. nemo_cli-0.1.0/docs/decisions/026-auth-session-layer.md +74 -0
  38. nemo_cli-0.1.0/docs/decisions/027-auth-command-group.md +63 -0
  39. nemo_cli-0.1.0/docs/decisions/_index.md +42 -0
  40. nemo_cli-0.1.0/docs/session-flow.md +145 -0
  41. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/pyproject.toml +2 -2
  42. nemo_cli-0.1.0/src/nemo_cli/__init__.py +1 -0
  43. nemo_cli-0.1.0/src/nemo_cli/api/client.py +77 -0
  44. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/auth/jwt.py +5 -0
  45. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/auth/service.py +9 -4
  46. nemo_cli-0.1.0/src/nemo_cli/auth/session.py +50 -0
  47. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/cli.py +2 -6
  48. nemo_cli-0.1.0/src/nemo_cli/commands/auth.py +22 -0
  49. nemo_cli-0.1.0/src/nemo_cli/commands/login.py +27 -0
  50. nemo_cli-0.1.0/src/nemo_cli/commands/status.py +29 -0
  51. nemo_cli-0.1.0/src/nemo_cli/config.py +1 -0
  52. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/api/test_client.py +48 -109
  53. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/auth/test_service.py +19 -36
  54. nemo_cli-0.1.0/tests/auth/test_session.py +62 -0
  55. nemo_cli-0.1.0/tests/commands/test_auth_commands.py +111 -0
  56. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/conftest.py +24 -11
  57. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/test_cli.py +2 -2
  58. nemo_cli-0.1.0/tests/test_config.py +10 -0
  59. nemo_cli-0.0.1/.env.example +0 -2
  60. nemo_cli-0.0.1/docs/decisions/_index.md +0 -15
  61. nemo_cli-0.0.1/src/nemo_cli/__init__.py +0 -1
  62. nemo_cli-0.0.1/src/nemo_cli/api/client.py +0 -81
  63. nemo_cli-0.0.1/src/nemo_cli/commands/login.py +0 -15
  64. nemo_cli-0.0.1/src/nemo_cli/commands/whoami.py +0 -18
  65. nemo_cli-0.0.1/src/nemo_cli/config.py +0 -24
  66. nemo_cli-0.0.1/tests/commands/test_auth_commands.py +0 -99
  67. nemo_cli-0.0.1/tests/test_config.py +0 -85
  68. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.claude/skills/new-decision/SKILL.md +0 -0
  69. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.claude/skills/status/SKILL.md +0 -0
  70. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/.gitignore +0 -0
  71. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/LICENSE +0 -0
  72. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/context-first-development.md +0 -0
  73. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/001-initial-architecture.md +0 -0
  74. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/002-tech-stack.md +0 -0
  75. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/003-token-authentication.md +0 -0
  76. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/004-switch-to-python-stack.md +0 -0
  77. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/006-instruments-domain.md +0 -0
  78. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/007-versioning-and-changelog.md +0 -0
  79. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/008-portfolio-domain.md +0 -0
  80. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/010-instrument-price-history.md +0 -0
  81. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/011-portfolio-movements.md +0 -0
  82. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/docs/decisions/012-refresh-token-flow.md +0 -0
  83. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/scripts/verify_reactive_fallback.py +0 -0
  84. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/scripts/verify_refresh.py +0 -0
  85. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/__main__.py +0 -0
  86. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/api/__init__.py +0 -0
  87. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/auth/__init__.py +0 -0
  88. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/auth/token_store.py +0 -0
  89. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/commands/__init__.py +0 -0
  90. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/commands/instruments.py +0 -0
  91. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/commands/logout.py +0 -0
  92. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/commands/portfolio.py +0 -0
  93. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/instruments/__init__.py +0 -0
  94. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/instruments/international.py +0 -0
  95. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/instruments/local.py +0 -0
  96. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/instruments/prices.py +0 -0
  97. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/portfolio/__init__.py +0 -0
  98. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/portfolio/movements.py +0 -0
  99. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/src/nemo_cli/portfolio/summary.py +0 -0
  100. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/__init__.py +0 -0
  101. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/api/__init__.py +0 -0
  102. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/auth/__init__.py +0 -0
  103. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/auth/test_jwt.py +0 -0
  104. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/auth/test_token_store.py +0 -0
  105. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/commands/__init__.py +0 -0
  106. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/commands/test_instruments_commands.py +0 -0
  107. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/commands/test_portfolio_commands.py +0 -0
  108. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/instruments/__init__.py +0 -0
  109. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/instruments/test_international.py +0 -0
  110. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/instruments/test_local.py +0 -0
  111. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/instruments/test_prices.py +0 -0
  112. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/portfolio/__init__.py +0 -0
  113. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/portfolio/test_movements.py +0 -0
  114. {nemo_cli-0.0.1 → nemo_cli-0.1.0}/tests/portfolio/test_summary.py +0 -0
@@ -0,0 +1,37 @@
1
+ ---
2
+ description: Close a CFD session by running the non-negotiable session-close ritual — update docs/CURRENT_STATUS.md, capture any clarified convention or informal decision, and produce a PR-ready summary. Use when the user says "close session", "wrap up", "we're done for today", or invokes the CFD session-close ritual. Implements ADR-018.
3
+ ---
4
+
5
+ Run the Context-First Development session-close ritual (ADR-018). This is
6
+ **non-negotiable** — a session that ends without step 1 leaves the next session
7
+ with stale context. Do all of the following, in order:
8
+
9
+ 1. **Update `docs/CURRENT_STATUS.md`:**
10
+ - Move completed items from "In Progress" to "Recently Completed".
11
+ - Add anything still pending or newly surfaced this session.
12
+ - Update "Known Issues / Open Questions" if anything new appeared.
13
+ - Re-rank "Next Priorities".
14
+ - Update the "Last updated" date to today.
15
+ - If work was tracked as a GitHub issue (ADR-021), reference it by `#N`.
16
+
17
+ 2. **Update `docs/CONVENTIONS.md`** if any convention was clarified or a pattern
18
+ was corrected this session (ADR-016). Do not leave corrections only in chat
19
+ history — they will be lost next session.
20
+
21
+ 3. **If a significant decision was made informally** (in chat, in passing),
22
+ propose creating an ADR via the `new-decision` skill before closing
23
+ (ADR-013). Do not let an implicit decision ship undocumented.
24
+
25
+ 4. **Ship `docs/` context changes in the same commit/PR as the session's code.**
26
+ Exception specific to this project: `docs/CURRENT_STATUS.md` is local-only
27
+ (gitignored), so it is updated locally every session but never travels in a
28
+ PR — only `CONVENTIONS.md` and ADRs do.
29
+
30
+ Do **not** end the session without completing step 1.
31
+
32
+ After completing the ritual, output a one-paragraph session summary suitable for
33
+ pasting into a PR description (Spanish is fine here per ADR-014 — PR descriptions
34
+ are not reloaded into context).
35
+
36
+ If a PR was opened from this session, the natural next step is the `review-pr`
37
+ skill — it cross-checks the diff against the project's checklist (ADR-020).
@@ -0,0 +1,63 @@
1
+ ---
2
+ description: Create a self-sufficient nemo-cli unit of work as a GitHub Issue with the fixed CFD body template (Context, Target, ADRs to load, Acceptance criteria, Reproduction, Estimated sessions). Use when the user asks to "open an issue", "create a work item", "plan a task", or describes new work to be tracked. Implements ADR-021.
3
+ ---
4
+
5
+ Guide the user through creating a GitHub Issue with the fixed body template from
6
+ ADR-021. The completeness of this issue determines how cheaply the next session
7
+ starts — be thorough here. Ask, in order, and confirm each answer:
8
+
9
+ 1. **Type.** `feature` | `fix` | `chore` | `spike` | `docs`.
10
+ 2. **Title.** Imperative, ≤ 80 chars, English (ADR-014). e.g. "Add `nemo
11
+ portfolio export` command".
12
+ 3. **Context.** 2–4 sentences: the trigger and the user-visible outcome.
13
+ 4. **Target location.** Concrete paths. For a new subcommand, name the module
14
+ and proposed file (e.g. `src/nemo_cli/commands/<verb>.py` — new file —
15
+ registered in `src/nemo_cli/cli.py`).
16
+ 5. **Pattern to mirror.** An existing file the implementation should copy in
17
+ shape and naming (e.g. `src/nemo_cli/commands/instruments.py`). Flag
18
+ explicitly if no analog exists.
19
+ 6. **ADRs to load.** ADR numbers the agent must read first. If a needed decision
20
+ is not yet an ADR, **STOP and run the `new-decision` skill** — implementing
21
+ an undocumented decision is forbidden by ADR-013.
22
+ 7. **Acceptance criteria (DoD).** Markdown `[ ]` items covering all three of:
23
+ behaviour at the end, tests (kind + location under `tests/` mirroring the
24
+ package tree, `respx`/`CliRunner` per CONVENTIONS, coverage ≥ 95%), and docs
25
+ updated (CONVENTIONS, ADRs, README, CHANGELOG per ADR-007).
26
+ 8. **Reproduction steps.** `fix` only — a minimal repro the agent can run.
27
+ 9. **Estimated sessions.** `1` | `2–3` | `4+`. If > 1, **propose decomposing
28
+ into sub-issues before continuing** (ADR-019).
29
+ 10. **Labels.** The type plus any component (`auth`, `instruments`, `portfolio`,
30
+ `api`, `ci`, …).
31
+
32
+ Then generate the body using the fixed template — do not change section order or
33
+ names; `issue-start` parses by header:
34
+
35
+ ```markdown
36
+ ## Context
37
+ <step 3>
38
+
39
+ ## Target
40
+ - Files / dirs: <step 4>
41
+ - Pattern to mirror: <step 5>
42
+
43
+ ## ADRs to load
44
+ - [ADR-NNN](docs/decisions/NNN-*.md)
45
+
46
+ ## Acceptance criteria
47
+ - [ ] <step 7>
48
+
49
+ ## Reproduction (fixes only)
50
+ <step 8 — OR omit this section entirely if not a fix>
51
+
52
+ ## Estimated sessions
53
+ <step 9>
54
+ ```
55
+
56
+ Then create it:
57
+
58
+ ```bash
59
+ gh issue create --title "<step 2>" --body "<body above>" --label "<type>,<labels>"
60
+ ```
61
+
62
+ Output the issue URL when done. English for the issue body (ADR-014); the issue
63
+ comment thread may be Spanish.
@@ -0,0 +1,39 @@
1
+ ---
2
+ description: Pick up a nemo-cli GitHub Issue as the focus of this session — fetch it, parse its fixed CFD sections, pre-load the ADRs it names, skim the pattern to mirror, and summarize the objective and acceptance checklist without scanning target files. Use when the user says "start issue", "work on #N", "pick up", or passes an issue number. Implements ADR-021.
3
+ ---
4
+
5
+ Pick up a tracker issue as this session's focus (ADR-021). Orient from the issue
6
+ body and its ADRs — do not scan code at this step.
7
+
8
+ 1. **Fetch the issue.** The user passes a number; if not, ask which.
9
+
10
+ ```bash
11
+ gh issue view <n>
12
+ ```
13
+
14
+ 2. **Parse the fixed sections** (ADR-021): `Context`, `Target`, `ADRs to load`,
15
+ `Acceptance criteria`, `Reproduction` (fixes only), `Estimated sessions`. If
16
+ a required section is missing, **STOP** — tell the user the issue is
17
+ malformed and propose fixing it via `gh issue edit <n>`. Do not infer.
18
+
19
+ 3. **Read each ADR listed in `ADRs to load`** from `docs/decisions/`. These set
20
+ the constraints the implementation must satisfy.
21
+
22
+ 4. **Read the `Pattern to mirror` file ONCE for shape.** Skim, don't study — the
23
+ goal is to know what the produced code should look like.
24
+
25
+ 5. **Do NOT read the `Target` files yet.** They are where the work *goes*, not
26
+ where context comes *from*; reading them now is wasted tokens.
27
+
28
+ 6. **Summarize for the user:**
29
+ - **Objective** (one line, from `Context`).
30
+ - **Acceptance checklist** (verbatim from `Acceptance criteria` — the DoD).
31
+ - **ADRs loaded** and what each constrains.
32
+ - **Target paths** you will write to.
33
+ - **Pattern to mirror.**
34
+
35
+ 7. Ask: **"Ready to start?"** If `Estimated sessions` > 1, remind the user the
36
+ issue should be decomposed and offer to split it via `issue-new` (ADR-019).
37
+
38
+ **Token discipline:** the issue body + ADRs are the spec. Code reading happens
39
+ when implementation starts, not during orientation.
@@ -0,0 +1,115 @@
1
+ ---
2
+ description: Review a nemo-cli Pull Request against the project's curated checklist — sourced from the ADRs, CONVENTIONS.md, and any linked issue's acceptance criteria — instead of re-discovering intent from code. Use when the user asks to "review PR", "review this branch", "check my PR", or passes a PR number. Implements ADR-020.
3
+ ---
4
+
5
+ Review a PR against the project's context (ADR-020), not by re-discovering its
6
+ intent from code. The agenda comes from the indices; read source to the depth
7
+ the checklist demands.
8
+
9
+ ## 1. Identify the PR
10
+
11
+ The user passes a PR number. If not, infer from the current branch:
12
+
13
+ ```bash
14
+ gh pr status --json number --jq '.currentBranch.number'
15
+ ```
16
+
17
+ If still none, ask.
18
+
19
+ ## 2. Fetch PR metadata + diff + commit story
20
+
21
+ ```bash
22
+ gh pr view <n> --json baseRefName,headRefName,title,body,labels,commits,closingIssuesReferences
23
+ gh pr diff <n>
24
+ git log <base>..<head> --pretty=format:%s
25
+ ```
26
+
27
+ ## 3. Load the agenda
28
+
29
+ - `docs/CONVENTIONS.md`
30
+ - `docs/decisions/_index.md`, plus every ADR named in the PR body or a linked
31
+ issue.
32
+ - The linked issue body via `gh issue view <issue-n>` if one exists (ADR-021):
33
+ extract the acceptance-criteria checklist and the "ADRs to load" list.
34
+ - `.github/PULL_REQUEST_TEMPLATE.md` if present.
35
+
36
+ ## 4. Read changed files to the depth the agenda demands
37
+
38
+ For nemo-cli this means **reading changed source files in full** — strict
39
+ `pyright` and the `api_request()` boundary rule require verifying call sites,
40
+ types, and that no handler or service calls `httpx` directly. This is
41
+ verification against known rules, not discovery.
42
+
43
+ ## 5. Apply the checklist
44
+
45
+ ### Workflow (ADR-005, ADR-014)
46
+
47
+ - Branch name follows `<type>/<slug>` (`feat`/`fix`/`docs`/`chore`/`refactor`/`test`).
48
+ - Base branch is `main`; merge will be a squash with a Conventional-Commits title.
49
+ - PR title is Conventional Commits and English.
50
+ - PR body references `Closes #<n>` when an issue exists (ADR-021).
51
+ - **No AI-attribution metadata** anywhere — no `Co-Authored-By:` trailer and no
52
+ "Generated with …" line, in any commit or the PR body (ADR-022). Flag any that
53
+ appear.
54
+
55
+ ### HTTP boundary (ADR-003, critical rule)
56
+
57
+ - All Vector-portal HTTP goes through `api_request()` in
58
+ `src/nemo_cli/api/client.py`. No `httpx.request(...)` in command handlers or
59
+ services. Only allowed exception: `nemo_cli.auth.service.sign_in`.
60
+ - Endpoint paths passed to `api_request()` are relative (e.g. `/shared/...`).
61
+ - A new slow endpoint overrides `timeout=` at the service layer and adds a row
62
+ to the Timeouts table in `CONVENTIONS.md` — the global default is unchanged.
63
+
64
+ ### Conventions (CONVENTIONS.md)
65
+
66
+ - Only `nemo_cli.config` reads `os.environ`.
67
+ - Imports are absolute; new subcommand = one module exporting one verb function,
68
+ registered in `cli.py`.
69
+ - Response shapes are typed at the call site (TypedDict/dataclass), not in a
70
+ global types module.
71
+ - Errors: command handlers print a red one-line message to stderr and raise
72
+ `typer.Exit(code=1)`; library code raises `RuntimeError`.
73
+ - A `--json` flag, when added, echoes the request scope + typed result.
74
+
75
+ ### Types
76
+
77
+ - `pyright` strict passes; explicit return types on public functions; PEP-604
78
+ unions (`str | None`); no `Any`.
79
+
80
+ ### Testing (CONVENTIONS.md)
81
+
82
+ - HTTP mocked via `respx`; CLI tested via `CliRunner`; tests mirror the package
83
+ tree; private helpers tested directly; coverage stays ≥ 95%.
84
+
85
+ ### Decisions & docs drift
86
+
87
+ - Any new significant decision has an ADR in this PR (ADR-013); `_index.md`
88
+ updated.
89
+ - A clarified convention is captured in `CONVENTIONS.md` (ADR-016).
90
+ - A user-facing change has a `CHANGELOG.md` entry (ADR-007).
91
+ - Each acceptance-criteria `[ ]` from the linked issue is implemented; no
92
+ out-of-scope changes.
93
+
94
+ ## 6. Output a structured review
95
+
96
+ ```text
97
+ ## Critical (must fix before merge)
98
+ - <file>:<line> — <issue> — citation: <ADR-N / CONVENTIONS line>. Suggested fix: <…>.
99
+
100
+ ## Suggestions (should fix)
101
+ - <file>:<line> — <issue> — citation.
102
+
103
+ ## Nits
104
+ - <file>:<line> — <issue>.
105
+
106
+ ## Summary
107
+ - Overall assessment, AC coverage X/Y, architecture compliance ✓/⚠/✗.
108
+ ```
109
+
110
+ ## Rules
111
+
112
+ - **Do NOT auto-fix.** Report only; the author fixes next session.
113
+ - If the checklist needs a rule not yet in an ADR or `CONVENTIONS.md`, surface
114
+ it as a finding ("missing convention for X") and propose `new-decision` — do
115
+ not silently invent it.
@@ -8,10 +8,24 @@ files, in order, and do not scan source code unless a follow-up question require
8
8
  1. `docs/CURRENT_STATUS.md` — what is in progress, what is blocked, what is next.
9
9
  2. `docs/decisions/_index.md` — recent decisions that may affect the next change.
10
10
 
11
+ 3. **If `CURRENT_STATUS.md` references in-progress work by issue number** (e.g.
12
+ `#142`), load that unit of work (ADR-021):
13
+
14
+ ```bash
15
+ gh issue view <n>
16
+ ```
17
+
18
+ Then read each ADR the issue lists under "ADRs to load" from
19
+ `docs/decisions/`. Do **not** read the files in the issue's "Target" section —
20
+ those are where the work goes, not where context comes from. If no issue is
21
+ referenced, skip this step and orient from `CURRENT_STATUS.md` alone.
22
+
11
23
  Then produce a brief (≤ 8 lines) summary covering:
12
24
 
13
25
  - What was being worked on in the previous session.
14
26
  - What is currently blocked and why.
27
+ - The objective and acceptance checklist of the in-progress issue, if one was
28
+ loaded in step 3.
15
29
  - What the next priority should be, based on `CURRENT_STATUS.md` and any open
16
30
  questions noted there.
17
31
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Audit CFD context-file integrity — verify CLAUDE.md size, @-references resolve, ADR index consistency, no duplicated context, and CURRENT_STATUS.md freshness. Use when the user asks to "validate context", "audit docs", or check whether the CFD scaffolding is healthy.
2
+ description: Audit CFD context-file integrity — verify CLAUDE.md size, @-references resolve, ADR index consistency, no duplicated context, English-only model context, skill-set consistency, and CURRENT_STATUS.md freshness. Use when the user asks to "validate context", "audit docs", or check whether the CFD scaffolding is healthy.
3
3
  ---
4
4
 
5
5
  Run a CFD context-integrity check. Do not modify files; just report findings.
@@ -18,7 +18,15 @@ Checks to perform:
18
18
  `docs/STACK.md` only (not also expanded inside `CLAUDE.md` or `ARCHITECTURE.md`),
19
19
  and that decision rationale is in the relevant ADR (not duplicated in
20
20
  `ARCHITECTURE.md`).
21
- 5. **`CURRENT_STATUS.md` freshness.** Look at the `Last updated:` line. If it is
21
+ 5. **English-only model context (ADR-014).** Spot-check that `CLAUDE.md` and
22
+ `docs/**/*.md` (including ADRs and `.claude/skills/**/SKILL.md`) are written in
23
+ English. Flag any model-facing file whose prose is predominantly another
24
+ language. (PR descriptions and chat are exempt — they are not in this tree.)
25
+ 6. **Skill-set consistency (ADR-015).** Every procedure listed in the
26
+ `docs/CONVENTIONS.md` "CFD workflow (Skills)" table has a matching
27
+ `.claude/skills/<name>/SKILL.md`, and every skill directory appears in that
28
+ table. Flag any mismatch in either direction.
29
+ 7. **`CURRENT_STATUS.md` freshness.** Look at the `Last updated:` line. If it is
22
30
  more than two working days behind today's date, flag it.
23
31
 
24
32
  Output a short report grouped by check, with `✓` / `✗` and a one-line note for each.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something in nemo-cli behaves incorrectly
4
+ title: "fix: "
5
+ labels: [bug]
6
+ ---
7
+
8
+ > ⚠️ **Never paste real credentials, bearer tokens, JWTs, RUTs, or real
9
+ > portfolio amounts.** Redact or use synthetic values.
10
+
11
+ ## What happened
12
+
13
+ <!-- A clear description of the bug and the command you ran. -->
14
+
15
+ ## Steps to reproduce
16
+
17
+ 1. <!-- e.g. `nemo portfolio summary --json` -->
18
+ 2.
19
+
20
+ ## Expected vs. actual
21
+
22
+ - **Expected:**
23
+ - **Actual:** <!-- include the error message, redacted -->
24
+
25
+ ## Environment
26
+
27
+ - `nemo --version`:
28
+ - Python version:
29
+ - OS:
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Security vulnerability (private)
4
+ url: https://github.com/albertomarturelo/nemo-cli/security/advisories/new
5
+ about: Report security issues privately. Do NOT open a public issue. See SECURITY.md.
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest a new command, flag, or capability
4
+ title: "feat: "
5
+ labels: [enhancement]
6
+ ---
7
+
8
+ ## Problem
9
+
10
+ <!-- What are you trying to do that nemo-cli doesn't support today? -->
11
+
12
+ ## Proposed solution
13
+
14
+ <!-- The command / flag / behaviour you'd like. e.g. a new subcommand,
15
+ a `--json` field, a new portal endpoint. -->
16
+
17
+ ## Scope
18
+
19
+ <!-- Which domain does this touch? auth / instruments / portfolio / output / other -->
20
+
21
+ ## Alternatives considered
22
+
23
+ <!-- Workarounds you've tried or other approaches. -->
@@ -0,0 +1,44 @@
1
+ ---
2
+ name: Work unit (maintainer)
3
+ about: Internal maintainer work unit (per ADR-021). Contributors — use Bug report or Feature request instead.
4
+ title: ""
5
+ labels: []
6
+ ---
7
+
8
+ <!-- Do NOT delete any section. The `issue-start` skill parses by section header.
9
+ If a section truly does not apply (e.g. Reproduction on a feature),
10
+ remove ONLY that section. -->
11
+
12
+ ## Context
13
+
14
+ <!-- 2–4 sentences: what is the trigger, what is the user-visible outcome. -->
15
+
16
+ ## Target
17
+
18
+ - Files / dirs: <!-- concrete paths; mark `new file` if net-new -->
19
+ - Pattern to mirror: <!-- existing file the implementation should mirror in shape/naming, e.g. src/nemo_cli/portfolio/summary.py -->
20
+
21
+ ## ADRs to load
22
+
23
+ <!-- ADR numbers the agent must read before starting. Link each one. -->
24
+
25
+ - [ADR-NNN](docs/decisions/NNN-*.md)
26
+
27
+ ## Acceptance criteria
28
+
29
+ <!-- Definition of Done — reused verbatim in the PR description. -->
30
+
31
+ - [ ] <!-- Behavior: what works at the end (concrete CLI output / library API) -->
32
+ - [ ] <!-- Tests: which tests/ files exist; respx-mocked, no real network -->
33
+ - [ ] <!-- Documentation: which of CONVENTIONS / STACK / ARCHITECTURE / CHANGELOG / new ADR is updated -->
34
+
35
+ ## Reproduction (fixes only)
36
+
37
+ <!-- ONLY for `fix` issues. Minimal repro the agent can run. Remove this
38
+ section entirely if not a fix. Never paste real credentials or RUTs. -->
39
+
40
+ ## Estimated sessions
41
+
42
+ <!-- 1 | 2–3 | 4+. If > 1, decompose into sub-issues before starting (ADR-019). -->
43
+
44
+ 1
@@ -0,0 +1,43 @@
1
+ <!-- Keep this template's sections — the `review-pr` skill (ADR-020) parses them. -->
2
+
3
+ ## Summary
4
+
5
+ <!-- 1-3 sentences: what the PR changes and why. -->
6
+
7
+ ## Linked issue
8
+
9
+ Closes #<!-- N -->
10
+
11
+ <!-- If no linked issue, replace this section with a justification.
12
+ Most non-trivial work should track an issue per ADR-021. -->
13
+
14
+ ## Acceptance criteria
15
+
16
+ <!-- Copy verbatim from the issue body. Tick boxes as items land. -->
17
+
18
+ - [ ] <!-- behavior -->
19
+ - [ ] <!-- tests -->
20
+ - [ ] <!-- documentation -->
21
+
22
+ ## ADRs touched
23
+
24
+ <!-- ADRs this PR depends on, supersedes, or amends. If you introduced a new
25
+ decision, link the new ADR file. If none, write "none". -->
26
+
27
+ - ADR-NNN
28
+
29
+ ## Test plan
30
+
31
+ <!-- Concrete commands a reviewer can run. HTTP is respx-mocked; no real
32
+ network or real credentials, ever (CONVENTIONS.md § Testing). -->
33
+
34
+ ```bash
35
+ pytest
36
+ ruff check .
37
+ pyright
38
+ ```
39
+
40
+ ## Notes for the reviewer
41
+
42
+ <!-- Anything non-obvious in the diff, deferred follow-ups, captured response
43
+ shapes for a new endpoint, etc. No AI-attribution footer in commits (ADR-022). -->
@@ -0,0 +1,170 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main]
6
+ push:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ tests:
18
+ name: Tests + Lint (py${{ matrix.python-version }})
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ python-version: ['3.11', '3.12', '3.13']
24
+ steps:
25
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
26
+
27
+ - name: Set up Python ${{ matrix.python-version }}
28
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
29
+ with:
30
+ python-version: ${{ matrix.python-version }}
31
+ cache: pip
32
+
33
+ - name: Install (editable + dev extras)
34
+ run: python -m pip install --upgrade pip && pip install -e .[dev]
35
+
36
+ - name: pytest (coverage gate >= 95%)
37
+ run: pytest --cov=nemo_cli --cov-report=term-missing --cov-fail-under=95
38
+
39
+ - name: ruff check
40
+ run: ruff check .
41
+
42
+ types:
43
+ name: Types (pyright strict)
44
+ runs-on: ubuntu-latest
45
+ steps:
46
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
47
+
48
+ - name: Set up Python
49
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
50
+ with:
51
+ python-version: '3.12'
52
+ cache: pip
53
+
54
+ - name: Install (editable + dev extras)
55
+ run: python -m pip install --upgrade pip && pip install -e .[dev]
56
+
57
+ - name: pyright
58
+ run: pyright
59
+
60
+ validate-context:
61
+ name: Validate context (ADRs + api_request boundary + PII)
62
+ runs-on: ubuntu-latest
63
+ steps:
64
+ - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
65
+
66
+ - name: ADR index integrity
67
+ # Every docs/decisions/NNN-*.md must be listed in _index.md, and every
68
+ # link from _index.md must point to a real file (the /validate-context
69
+ # skill, check #3).
70
+ run: |
71
+ set -euo pipefail
72
+ fail=0
73
+ for f in docs/decisions/[0-9]*.md; do
74
+ name=$(basename "$f")
75
+ if ! grep -q "$name" docs/decisions/_index.md; then
76
+ echo "::error file=docs/decisions/_index.md::ADR $name exists on disk but is not listed in the index."
77
+ fail=1
78
+ fi
79
+ done
80
+ while IFS= read -r ref; do
81
+ if [ -n "$ref" ] && [ ! -f "$ref" ]; then
82
+ echo "::error file=docs/decisions/_index.md::Index links to a missing file: $ref"
83
+ fail=1
84
+ fi
85
+ done < <(grep -oE 'docs/decisions/[0-9]+-[a-zA-Z0-9-]+\.md' docs/decisions/_index.md | sort -u)
86
+ exit $fail
87
+
88
+ - name: ADR completeness (5 mandatory sections)
89
+ # House ADR format: Status, Context, Decision, Alternatives Considered,
90
+ # Consequences (Date is also present but not gated here).
91
+ run: |
92
+ set -euo pipefail
93
+ fail=0
94
+ for f in docs/decisions/[0-9]*.md; do
95
+ for section in '## Status' '## Context' '## Decision' '## Alternatives Considered' '## Consequences'; do
96
+ if ! grep -qxF "$section" "$f"; then
97
+ echo "::error file=$f::Missing required ADR section '$section'."
98
+ fail=1
99
+ fi
100
+ done
101
+ done
102
+ exit $fail
103
+
104
+ - name: CLAUDE.md is an index (<= 150 lines)
105
+ run: |
106
+ set -euo pipefail
107
+ lines=$(wc -l < CLAUDE.md)
108
+ if [ "$lines" -gt 150 ]; then
109
+ echo "::error file=CLAUDE.md::CLAUDE.md is $lines lines (> 150) — it must stay an index of @-references, not a long-form doc."
110
+ exit 1
111
+ fi
112
+ echo "CLAUDE.md: $lines lines (<= 150)."
113
+
114
+ - name: CLAUDE.md @-references resolve
115
+ run: |
116
+ set -euo pipefail
117
+ fail=0
118
+ for ref in $(grep -oE '@[A-Za-z0-9_./-]+' CLAUDE.md | sed 's/^@//'); do
119
+ if [ ! -e "$ref" ]; then
120
+ echo "::error file=CLAUDE.md::@-reference does not resolve: $ref"
121
+ fail=1
122
+ fi
123
+ done
124
+ exit $fail
125
+
126
+ - name: Skill-set consistency (ADR-015)
127
+ # Every skill under .claude/skills/ is listed in the CONVENTIONS
128
+ # "CFD workflow (Skills)" table, and vice versa.
129
+ run: |
130
+ set -euo pipefail
131
+ section=$(awk '/^## CFD workflow/{f=1} f&&/^## /&&!/CFD workflow/{exit} f' docs/CONVENTIONS.md)
132
+ dirs=$(ls -1 .claude/skills | sort)
133
+ table=$(printf '%s\n' "$section" | grep -oE '`[a-z][a-z-]+`' | tr -d '`' | sort -u)
134
+ if ! diff <(printf '%s\n' "$dirs") <(printf '%s\n' "$table") >/dev/null; then
135
+ echo "::error file=docs/CONVENTIONS.md::Skill set mismatch between .claude/skills/ and the CONVENTIONS 'CFD workflow' table:"
136
+ diff <(printf '%s\n' "$dirs") <(printf '%s\n' "$table") || true
137
+ exit 1
138
+ fi
139
+ echo "Skill set consistent."
140
+
141
+ - name: api_request() boundary (ADR-003)
142
+ # All Vector-portal HTTP must go through api_request(); the only files
143
+ # allowed to touch httpx directly are the client and the auth bootstrap.
144
+ run: |
145
+ set -euo pipefail
146
+ if git grep -nE 'httpx\.(request|get|post|put|delete|patch|stream|Client|AsyncClient)' -- 'src/' ':!src/nemo_cli/api/client.py' ':!src/nemo_cli/auth/service.py'; then
147
+ echo "::error::Direct httpx use outside api_request()/sign_in — ADR-003 forbids. Route the call through api_request() in src/nemo_cli/api/client.py."
148
+ exit 1
149
+ fi
150
+ echo "ADR-003 guard: no direct httpx use outside the allowed files."
151
+
152
+ - name: PII guard (no real RUTs in tracked files)
153
+ # CONVENTIONS forbids real PII in committed files. The synthetic dummy
154
+ # RUT (12.345.678-*) is allowed in tests/docs. Real RUT digit-bodies
155
+ # live in the PII_RUT_DENYLIST secret (pipe-separated 8-digit bodies, no
156
+ # dots/DV) — kept out of this public file. On forks the secret is unset
157
+ # and this step is skipped.
158
+ env:
159
+ PII_RUT_DENYLIST: ${{ secrets.PII_RUT_DENYLIST }}
160
+ run: |
161
+ set -euo pipefail
162
+ if [ -z "${PII_RUT_DENYLIST:-}" ]; then
163
+ echo "PII guard: no denylist secret configured (fork or unset) — skipping."
164
+ exit 0
165
+ fi
166
+ if git grep -nE "$PII_RUT_DENYLIST" -- src/ tests/ docs/ pyproject.toml; then
167
+ echo "::error::Real RUT digits found in tracked files — PII leak per CONVENTIONS. Use a synthetic value (e.g. 12.345.678-0)."
168
+ exit 1
169
+ fi
170
+ echo "PII guard: no forbidden RUT digits found."
@@ -12,10 +12,10 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
14
  - name: Checkout
15
- uses: actions/checkout@v4
15
+ uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
16
16
 
17
17
  - name: Set up Python
18
- uses: actions/setup-python@v5
18
+ uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
19
19
  with:
20
20
  python-version: '3.12'
21
21
 
@@ -26,7 +26,7 @@ jobs:
26
26
  run: python -m build
27
27
 
28
28
  - name: Upload artifacts
29
- uses: actions/upload-artifact@v4
29
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
30
30
  with:
31
31
  name: python-package-distributions
32
32
  path: dist/
@@ -42,7 +42,7 @@ jobs:
42
42
  id-token: write
43
43
  steps:
44
44
  - name: Download artifacts
45
- uses: actions/download-artifact@v4
45
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
46
46
  with:
47
47
  name: python-package-distributions
48
48
  path: dist/
@@ -64,7 +64,7 @@ jobs:
64
64
  id-token: write
65
65
  steps:
66
66
  - name: Download artifacts
67
- uses: actions/download-artifact@v4
67
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
68
68
  with:
69
69
  name: python-package-distributions
70
70
  path: dist/