shakers-cli-beta 0.8.0-beta.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/LICENSE +59 -0
- package/README.md +1175 -0
- package/bin/add-agent.js +88 -0
- package/bin/add-project.js +88 -0
- package/bin/add-role.js +61 -0
- package/bin/add-skill.js +88 -0
- package/bin/ai-usage.js +81 -0
- package/bin/alma.js +99 -0
- package/bin/applications.js +69 -0
- package/bin/availability.js +70 -0
- package/bin/certifications.js +69 -0
- package/bin/certify.js +73 -0
- package/bin/change-role.js +61 -0
- package/bin/config.js +120 -0
- package/bin/experiences.js +69 -0
- package/bin/find-projects.js +89 -0
- package/bin/invitations.js +69 -0
- package/bin/lang.js +70 -0
- package/bin/login.js +283 -0
- package/bin/mcp.js +98 -0
- package/bin/me.js +69 -0
- package/bin/onboarding.js +134 -0
- package/bin/portfolios.js +69 -0
- package/bin/rate.js +70 -0
- package/bin/register.js +325 -0
- package/bin/report-html.js +134 -0
- package/bin/save.js +77 -0
- package/bin/shakers.js +344 -0
- package/bin/share.js +72 -0
- package/bin/show-project.js +72 -0
- package/bin/socials.js +70 -0
- package/bin/superadmin.js +351 -0
- package/package.json +40 -0
- package/src/agent-category.js +13 -0
- package/src/agent-evaluation.js +177 -0
- package/src/agent-org-chart.js +355 -0
- package/src/agent-synthesis.js +132 -0
- package/src/agent-usage.js +118 -0
- package/src/agents-client.js +165 -0
- package/src/ai-fluency-cell.js +72 -0
- package/src/ai-profile-client.js +45 -0
- package/src/ai-profile-preview.js +154 -0
- package/src/ai.js +66 -0
- package/src/alma-client.js +123 -0
- package/src/alma-flow.js +32 -0
- package/src/alma-repo-context.js +47 -0
- package/src/alma-shell.js +161 -0
- package/src/ansi.js +62 -0
- package/src/applications-client.js +79 -0
- package/src/applications-flow.js +58 -0
- package/src/auth-client.js +144 -0
- package/src/auth-device-client.js +118 -0
- package/src/auth-method-picker.js +44 -0
- package/src/auth-methods.js +35 -0
- package/src/auth-session-store.js +214 -0
- package/src/authorship.js +203 -0
- package/src/automations-detector.js +170 -0
- package/src/availability-client.js +92 -0
- package/src/availability-flow.js +105 -0
- package/src/backend-request.js +170 -0
- package/src/blind-approval-extract.js +48 -0
- package/src/brand-ansi.js +14 -0
- package/src/brand-svg.js +9 -0
- package/src/browser-tools-detector.js +21 -0
- package/src/build-next-level.js +56 -0
- package/src/certifications-client.js +89 -0
- package/src/certifications-flow.js +75 -0
- package/src/certify-dimension-client.js +217 -0
- package/src/certify-dimension-flow.js +193 -0
- package/src/certify-disclaimer.js +51 -0
- package/src/certify-remediation-prompt.js +23 -0
- package/src/cli-args.js +83 -0
- package/src/config-dir.js +120 -0
- package/src/config.js +778 -0
- package/src/consent-flow.js +115 -0
- package/src/consent-skip.js +27 -0
- package/src/decisions-extract.js +43 -0
- package/src/detect-repos.js +145 -0
- package/src/detected-tools.js +15 -0
- package/src/detection-evidence.js +105 -0
- package/src/detection-noise.js +132 -0
- package/src/detectors.js +221 -0
- package/src/device-auth-store.js +100 -0
- package/src/device-login.js +118 -0
- package/src/email-verification.js +152 -0
- package/src/env-paths.js +16 -0
- package/src/find-projects-cache.js +89 -0
- package/src/find-projects-client.js +138 -0
- package/src/find-projects-flow.js +164 -0
- package/src/git-activity.js +123 -0
- package/src/graph-certs.js +58 -0
- package/src/graph-generator.js +230 -0
- package/src/graph-scan.js +239 -0
- package/src/i18n.js +3264 -0
- package/src/inter-fonts.js +6 -0
- package/src/interactive-select.js +183 -0
- package/src/interview-client.js +226 -0
- package/src/interview-transcript.js +56 -0
- package/src/inventory-client.js +90 -0
- package/src/invitations-client.js +66 -0
- package/src/invitations-flow.js +50 -0
- package/src/lang-client.js +147 -0
- package/src/lang-codes.js +14 -0
- package/src/lang-flow.js +85 -0
- package/src/legal-notice.js +53 -0
- package/src/locale.js +51 -0
- package/src/markdown-ansi.js +50 -0
- package/src/maturity.js +111 -0
- package/src/mcp-ai-usage-result-tool.js +109 -0
- package/src/mcp-ai-usage-tool.js +333 -0
- package/src/mcp-alma-tools.js +91 -0
- package/src/mcp-applications-tools.js +42 -0
- package/src/mcp-ask-tools.js +50 -0
- package/src/mcp-auth-form.js +282 -0
- package/src/mcp-availability-tools.js +43 -0
- package/src/mcp-certifications-tools.js +42 -0
- package/src/mcp-certify-dimension-tools.js +58 -0
- package/src/mcp-detector.js +223 -0
- package/src/mcp-device-login-tools.js +173 -0
- package/src/mcp-find-projects-tools.js +67 -0
- package/src/mcp-install.js +245 -0
- package/src/mcp-invitations-tools.js +42 -0
- package/src/mcp-lang-tools.js +39 -0
- package/src/mcp-onboarding-tools.js +388 -0
- package/src/mcp-portfolios-tools.js +46 -0
- package/src/mcp-profile-tools.js +46 -0
- package/src/mcp-rate-tools.js +42 -0
- package/src/mcp-register-tools.js +517 -0
- package/src/mcp-report-tools.js +101 -0
- package/src/mcp-role-tools.js +112 -0
- package/src/mcp-saved-positions-tools.js +55 -0
- package/src/mcp-server.js +170 -0
- package/src/mcp-show-project-tools.js +50 -0
- package/src/mcp-socials-tools.js +39 -0
- package/src/memory-structure-detector.js +108 -0
- package/src/model-call-record.js +198 -0
- package/src/onboarding-availability.js +26 -0
- package/src/onboarding-client.js +364 -0
- package/src/onboarding-flow.js +1078 -0
- package/src/onboarding-livekit-client.js +102 -0
- package/src/onboarding-status-client.js +42 -0
- package/src/open-file.js +32 -0
- package/src/osc-link.js +16 -0
- package/src/portfolio-client.js +164 -0
- package/src/portfolio-git-info.js +61 -0
- package/src/portfolios-client.js +85 -0
- package/src/portfolios-flow.js +79 -0
- package/src/profile-client.js +125 -0
- package/src/profile-flow.js +115 -0
- package/src/profile-switch.js +46 -0
- package/src/prompt-select.js +29 -0
- package/src/rate-client.js +82 -0
- package/src/rate-flow.js +137 -0
- package/src/render-ai-fluency.js +266 -0
- package/src/render-certification.js +177 -0
- package/src/render-html.js +140 -0
- package/src/render-report-text.js +27 -0
- package/src/render-sheet.js +261 -0
- package/src/render-terminal.js +109 -0
- package/src/render-usage-report-text.js +155 -0
- package/src/repo-context.js +215 -0
- package/src/report-gating.js +49 -0
- package/src/report-store.js +226 -0
- package/src/report-theme.js +177 -0
- package/src/report-view-client.js +50 -0
- package/src/reveal-output.js +29 -0
- package/src/roadmap-content.js +453 -0
- package/src/roadmap-personalization.js +132 -0
- package/src/roadmap-prompt.js +154 -0
- package/src/roles-client.js +114 -0
- package/src/roles-flow.js +192 -0
- package/src/sanitize-network-text.js +36 -0
- package/src/saved-positions-client.js +71 -0
- package/src/saved-positions-flow.js +50 -0
- package/src/scan-exclusions.js +50 -0
- package/src/scanner.js +612 -0
- package/src/scope-signals.js +148 -0
- package/src/secret-prompt.js +72 -0
- package/src/session-gate.js +30 -0
- package/src/session-refresh.js +51 -0
- package/src/session-scan.js +336 -0
- package/src/session-signals.js +36 -0
- package/src/shakers-wordmark.js +17 -0
- package/src/share-card.js +362 -0
- package/src/share-certification.js +111 -0
- package/src/share-consent-state.js +157 -0
- package/src/share-payload.js +300 -0
- package/src/share.js +184 -0
- package/src/show-project-client.js +58 -0
- package/src/show-project-flow.js +119 -0
- package/src/signup-client.js +91 -0
- package/src/skills-client.js +102 -0
- package/src/socials-client.js +91 -0
- package/src/socials-flow.js +83 -0
- package/src/specificity-extract.js +41 -0
- package/src/start-add-agents.js +306 -0
- package/src/start-add-portfolio.js +388 -0
- package/src/start-add-skills.js +260 -0
- package/src/stdin-ask.js +129 -0
- package/src/steering-extract.js +43 -0
- package/src/strip-internal-comments.js +45 -0
- package/src/tech-detector.js +295 -0
- package/src/templates/report-sheet.html +572 -0
- package/src/terminal-agents.js +199 -0
- package/src/terminal-format.js +85 -0
- package/src/terminal-progress.js +106 -0
- package/src/terminal-sections.js +219 -0
- package/src/tier-analysis.js +126 -0
- package/src/tier-engine.js +114 -0
- package/src/tier-projection.js +117 -0
- package/src/transcript-turns.js +49 -0
- package/src/translations-client.js +84 -0
- package/src/typewriter.js +154 -0
- package/src/usage-model-calls.js +119 -0
- package/src/usage-oneshot-commands.js +180 -0
- package/src/usage-repo-scope.js +162 -0
- package/src/usage-run-steps.js +338 -0
- package/src/work-streams.js +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,1175 @@
|
|
|
1
|
+
# Shakers `shakers`
|
|
2
|
+
|
|
3
|
+
A **local-first** Shakers CLI (`shakers`) — a plain argument dispatcher:
|
|
4
|
+
`shakers <command> [flags]` runs one command and exits; run `shakers` with no
|
|
5
|
+
command to print the usage help. There is no interactive shell (the former
|
|
6
|
+
REPL was retired — ADR-060). Its commands:
|
|
7
|
+
|
|
8
|
+
- **`ai-usage`** — builds, **locally**, a deterministic profile of your AI
|
|
9
|
+
tool setup: which copilots/agents you have configured, how deep that
|
|
10
|
+
configuration goes, and what "level-up" **tier** (T0-T7) you're at. Its
|
|
11
|
+
terminal output leads with **why** you're at that tier, then the score, your
|
|
12
|
+
tools, technologies and a **one-line-per-agent** summary (each agent scored
|
|
13
|
+
for how well it's built + how often you've actually used it). The tier
|
|
14
|
+
roadmap / next-steps is available behind `--roadmap`.
|
|
15
|
+
- **`certify`** — certifies Skills from your Shakers catalog by analyzing your
|
|
16
|
+
local project's code (resolve which Skills apply, then sample and send
|
|
17
|
+
secret-scrubbed code for a per-Skill assessment), and certifies how deeply
|
|
18
|
+
you command your own agents (`certify agents`) through an interview. Both
|
|
19
|
+
require you to be [logged in](#login-login--logout) first.
|
|
20
|
+
- **`report`** — builds and **opens** the full, shareable HTML report for the
|
|
21
|
+
current project (usage + certified Skills, with the complete per-agent
|
|
22
|
+
detail). `ai-usage`/`certify` persist their result silently; `report` is how
|
|
23
|
+
you produce and open the HTML to share with your team.
|
|
24
|
+
- **`share`** — *(temporarily disabled)* turns the project's latest `ai-usage`
|
|
25
|
+
result (tier + score) into a branded card you can post on LinkedIn (built
|
|
26
|
+
offline; the PNG is exported in your browser). Invoking it prints a disabled
|
|
27
|
+
notice and runs nothing.
|
|
28
|
+
- **`login` / `logout`** — identify yourself as a registered Talent (email
|
|
29
|
+
or Google). See [Login](#login-login--logout).
|
|
30
|
+
- **`add-role` / `change-role`** — manage your roles: add a growth role from the
|
|
31
|
+
catalog, or switch your MAIN role to one you already hold (arrow-key pickers).
|
|
32
|
+
The onboarding interview also ends with the same MAIN-role step. See
|
|
33
|
+
[Command families](#command-families) for the `role`/`profile`/`add` groupings.
|
|
34
|
+
- **`superadmin`** — a non-production, password-gated test tool for the team
|
|
35
|
+
running this CLI against the service; not something a Talent uses. See
|
|
36
|
+
[Superadmin](#superadmin-non-production-only).
|
|
37
|
+
|
|
38
|
+
**Session gating (ADR-061).** `ai-usage` is the only command a non-registered
|
|
39
|
+
(session-less) caller can run — the anonymous AI-usage evaluation, with its
|
|
40
|
+
consent → email → persistence flow. Every other command requires an active
|
|
41
|
+
session: exempt are `ai-usage` and `login`; `logout` without a session is a
|
|
42
|
+
silent no-op; `certify`/`report`/`share` require `shakers login` first
|
|
43
|
+
(`superadmin` is its own non-prod escape hatch, exempt too). A session-less
|
|
44
|
+
call to a gated command prints a clear error naming what is missing and both
|
|
45
|
+
`shakers login` and `shakers register`; in non-TTY/agent mode it exits with a
|
|
46
|
+
non-zero code. `ai-usage` is public: when no session exists it only reminds the
|
|
47
|
+
Talent they can sign in (a Yes/No prompt on a TTY), never blocks. The former
|
|
48
|
+
standalone `ai-footprint`/`ai-certify` binaries were retired earlier; the
|
|
49
|
+
interactive shell that replaced them is now retired too (see
|
|
50
|
+
[`docs/decisions.md`](docs/decisions.md): ADR-060 REPL→argv, ADR-061 gating).
|
|
51
|
+
|
|
52
|
+
The AI usage mechanism is inspired by `darnoux/claude-code-level-up` (scan
|
|
53
|
+
local signals and classify by level), extended to cover the main AI tools on
|
|
54
|
+
the market (not just Claude) and to a full 8-tier ladder with per-tier roadmap
|
|
55
|
+
content.
|
|
56
|
+
|
|
57
|
+
## What it does
|
|
58
|
+
|
|
59
|
+
1. **Scans** the current project (and relevant parts of your home
|
|
60
|
+
directory) for known AI-tool configuration.
|
|
61
|
+
2. **Classifies** the setup into a tier, `T0` to `T7` ("empty bench" to
|
|
62
|
+
"orchestrated workshop"), computed deterministically — no LLM involved
|
|
63
|
+
in the level itself.
|
|
64
|
+
3. **Leads with a "why this tier" analysis**: exactly which criteria you meet,
|
|
65
|
+
with the signal behind each one, and the single next criterion blocking
|
|
66
|
+
progression to the next tier — shown FIRST, before the score.
|
|
67
|
+
4. **Evaluates your agents**: one line per agent (nested subagents drawn with
|
|
68
|
+
stacked `↓`), each with a **definition-quality score** (0-100, how well the
|
|
69
|
+
agent is built) and a **usage signal** (how often you've actually invoked it,
|
|
70
|
+
read from your local Claude Code history — usage only, never session
|
|
71
|
+
content). Full per-agent detail (rationale included) lives in the `report`
|
|
72
|
+
HTML.
|
|
73
|
+
5. **Roadmap behind `--roadmap`**: current tier → next tier, with what it
|
|
74
|
+
unlocks, steps, a copyable code snippet, community tips and common mistakes,
|
|
75
|
+
plus a ready-to-paste implementation prompt — curated, authored content, not
|
|
76
|
+
generated per run. Hidden from the default output to keep the terminal clean;
|
|
77
|
+
pass `--roadmap` (alias `--next`) to see it.
|
|
78
|
+
|
|
79
|
+
Everything above runs **always, locally, unconditionally** — nothing is
|
|
80
|
+
gated behind a decision. See [Privacy & consent](#privacy--consent-model)
|
|
81
|
+
for what happens if you choose to save your report to Shakers.
|
|
82
|
+
|
|
83
|
+
### Agent evaluation (the LLM feature)
|
|
84
|
+
|
|
85
|
+
The definition-quality score is the one AI-model-backed part of `ai-usage`. As
|
|
86
|
+
with the org-chart synthesis and roadmap personalization, the CLI never calls a
|
|
87
|
+
model directly: it POSTs the scrubbed agent definitions to the certifications
|
|
88
|
+
service's `agent-evaluation` endpoint (a sibling of your configured ingest
|
|
89
|
+
endpoint) that runs the model server-side (**gemini-2.5-flash**) and returns a
|
|
90
|
+
score + short rationale per agent. It degrades gracefully: no endpoint, a network error, or a
|
|
91
|
+
timeout simply means no scores are shown — the rest of the report is unaffected.
|
|
92
|
+
The **usage** signal is entirely local (no network, no model). See
|
|
93
|
+
[Privacy & consent](#privacy--consent-model).
|
|
94
|
+
|
|
95
|
+
## Installation
|
|
96
|
+
|
|
97
|
+
One line:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
curl -fsSL https://raw.githubusercontent.com/devShakers/ai-usage-evaluator/main/install.sh | bash
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The installer:
|
|
104
|
+
|
|
105
|
+
- Requires **Node 18+** (checks and fails clearly if missing/too old).
|
|
106
|
+
- Discovers the CLI's own `src/*.js` modules dynamically (via a local copy
|
|
107
|
+
or the GitHub API) rather than hardcoding a file list.
|
|
108
|
+
- Places the tool in `~/.shakers/` and drops the single `shakers`
|
|
109
|
+
command in `~/.local/bin` (the standalone `ai-footprint`/`ai-certify`
|
|
110
|
+
launchers are no longer created, and any legacy ones are removed on
|
|
111
|
+
upgrade). The only third-party package is **`@livekit/rtc-node`** (the
|
|
112
|
+
LiveKit interview engine), fetched post-install for every flavor;
|
|
113
|
+
`SHAKERS_SKIP_NATIVE_INSTALL=1` skips that fetch (offline installs / CI).
|
|
114
|
+
- All installer output is in English, unconditionally (it runs before
|
|
115
|
+
Node/the CLI's own i18n layer is available).
|
|
116
|
+
|
|
117
|
+
Alternative, cloning the repo first (same result, lets you review the code
|
|
118
|
+
before installing):
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
git clone https://github.com/devShakers/ai-usage-evaluator
|
|
122
|
+
cd ai-usage-evaluator
|
|
123
|
+
./install.sh
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Uninstall: `./install.sh --uninstall`.
|
|
127
|
+
|
|
128
|
+
## Publishing (maintainers)
|
|
129
|
+
|
|
130
|
+
One codebase ships in three flavors; the baked backend target is derived from
|
|
131
|
+
the package **name** (`src/config.js#PACKAGE_NAME_ENV`), overridable per run
|
|
132
|
+
with `SHAKERS_CLI_ENV=staging|dev|local`. Per-endpoint `SHAKERS_CLI_*_BASE`
|
|
133
|
+
env vars and `config.json` always win over the baked default.
|
|
134
|
+
|
|
135
|
+
| Flavor | Package name | Registry | Baked target | Publish |
|
|
136
|
+
|---|---|---|---|---|
|
|
137
|
+
| Private (current) | `@shakers/shakers-cli` | GitLab proj 201 (`publishConfig`) | dev (new-works) | `export SHAKERS_GITLAB_TOKEN=<PAT, scope write_registry on proj 201>` then `npm publish` |
|
|
138
|
+
| Public beta | `shakers-cli-beta` | npmjs (public) | staging | `node scripts/prepare-beta.js` → `npm publish --tag beta` → `git checkout -- package.json` |
|
|
139
|
+
| Local | (checkout, `@shakers/shakers-cli`) | — | dev, or `SHAKERS_CLI_ENV=local` for localhost | run from the clone; no publish |
|
|
140
|
+
|
|
141
|
+
Both publishes bump `version` first (the registry rejects re-publishing an
|
|
142
|
+
existing version). The private one publishes from a checked-out `main` with the
|
|
143
|
+
committed `@shakers/shakers-cli` manifest, unchanged. The beta one uses
|
|
144
|
+
`scripts/prepare-beta.js` to stamp `name`/`version`/`publishConfig` (version
|
|
145
|
+
`0.8.0-beta.0`, dist-tag `beta`), publishes, then restores the manifest with
|
|
146
|
+
git. The npmjs org/account for `shakers-cli-beta` must exist and you must be
|
|
147
|
+
`npm login`ed to it (or set `NODE_AUTH_TOKEN`) before publishing — nothing here
|
|
148
|
+
publishes automatically.
|
|
149
|
+
|
|
150
|
+
`@livekit/rtc-node` is a real `dependencies` entry, so `npm i` / `npm i -g` of
|
|
151
|
+
either package pulls it automatically (GitLab's packument keeps `dependencies`
|
|
152
|
+
but strips `optionalDependencies`, which is why it must not be optional).
|
|
153
|
+
|
|
154
|
+
## Usage
|
|
155
|
+
|
|
156
|
+
`shakers <command> [flags]` runs one command and exits. With no command it
|
|
157
|
+
prints the usage help:
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
shakers # print the usage help and exit
|
|
161
|
+
shakers --lang es|en # force the CLI copy language instead of OS-locale detect
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
The commands (only `ai-usage` and `login` run without a session — see
|
|
165
|
+
[Session gating](#shakers-shakers)):
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
shakers ai-usage # scan this project + machine, print the report (no HTML link) — anonymous
|
|
169
|
+
shakers certify # certify a DIMENSION of your role over a LiveKit interview (needs login)
|
|
170
|
+
shakers report # build + open the full shareable HTML report (needs login)
|
|
171
|
+
shakers share # branded LinkedIn card (temporarily disabled)
|
|
172
|
+
shakers login # identify yourself as a registered Talent (email or Google)
|
|
173
|
+
shakers logout # forget the stored session (no-op if none)
|
|
174
|
+
shakers superadmin # non-production test tool — not for Talents
|
|
175
|
+
|
|
176
|
+
# Marketplace & profile (all need login):
|
|
177
|
+
shakers alma # interactive mini-shell to chat with Alma, your AI assistant
|
|
178
|
+
shakers find-projects # list the Projects/Positions available to you (paginated, filterable)
|
|
179
|
+
shakers show-project # detail of one project/position (by number or id)
|
|
180
|
+
shakers save-project # bookmark a project/position (by number or id)
|
|
181
|
+
shakers unsave-project # remove a bookmark (by number or id)
|
|
182
|
+
shakers applications # projects you applied to + status
|
|
183
|
+
shakers invitations # your unread project invitations
|
|
184
|
+
shakers availability # view (or --set) your availability
|
|
185
|
+
shakers rate # view (or --set) your per-project rate
|
|
186
|
+
shakers certifications# your certified / uncertified / expired role dimensions
|
|
187
|
+
shakers add-role # add a role to your profile (a growth role) — arrow-key picker
|
|
188
|
+
shakers change-role # switch your MAIN role to one you already have — arrow-key picker
|
|
189
|
+
shakers me # your profile summary (alias: shakers profile)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
#### Command families
|
|
193
|
+
|
|
194
|
+
The flat commands above are also grouped into **families** — a friendlier way to
|
|
195
|
+
discover them for both humans and agents. `shakers <family> <subcommand>` runs the
|
|
196
|
+
exact same handler; **every flat command keeps working as an alias**, so nothing
|
|
197
|
+
breaks. Run `shakers <family>` with no subcommand to list its subcommands, and
|
|
198
|
+
`shakers` (no args) prints the full family map.
|
|
199
|
+
|
|
200
|
+
| Family | Subcommands | Flat aliases |
|
|
201
|
+
|--------|-------------|--------------|
|
|
202
|
+
| `add` | `skill`, `agent`, `project`, `role` | `add-skill`, `add-agent`, `add-project`, `add-role` |
|
|
203
|
+
| `role` | `add`, `change` (`main`) | `add-role`, `change-role` |
|
|
204
|
+
| `profile` | `show`, `rate`, `languages`, `socials`, `experiences`, `portfolios`, `availability`, `certifications` | `me`, `rate`, `lang`, `socials`, `experiences`, `portfolios`, `availability`, `certifications` |
|
|
205
|
+
| `projects` | `find`, `show`, `save`, `unsave`, `invitations`, `applications` | `find-projects`, `show-project`, `save-project`, `unsave-project`, `invitations`, `applications` |
|
|
206
|
+
| `usage` | `run`, `report`, `share` | `ai-usage`, `report`, `share` |
|
|
207
|
+
| `certs` | `list`, `certify` | `certifications`, `certify` |
|
|
208
|
+
| `account` | `login`, `logout`, `register`, `config` | `login`, `logout`, `register`, `config` |
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
shakers role add # == shakers add-role
|
|
212
|
+
shakers role change # == shakers change-role
|
|
213
|
+
shakers profile rate # == shakers rate
|
|
214
|
+
shakers projects find # == shakers find-projects
|
|
215
|
+
shakers usage run # == shakers ai-usage
|
|
216
|
+
shakers account login # == shakers login
|
|
217
|
+
shakers profile # no subcommand → your profile summary (== shakers me)
|
|
218
|
+
shakers projects # no subcommand → lists the "projects" subcommands
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Each command keeps all its flags:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
shakers ai-usage --json # report as JSON on stdout
|
|
225
|
+
shakers ai-usage --root ../other # scan another directory instead of the current one
|
|
226
|
+
shakers ai-usage --roadmap # also show the tier roadmap / next-steps (hidden by default; alias --next)
|
|
227
|
+
shakers ai-usage --no-save # persist nothing (report only, on screen)
|
|
228
|
+
shakers ai-usage --build-next-level # secondary path: write deterministic starter file(s) for the next tier
|
|
229
|
+
shakers ai-usage --force # with --build-next-level, overwrite an existing file
|
|
230
|
+
shakers ai-usage --lang es|en # force the report language instead of OS-locale detect
|
|
231
|
+
shakers ai-usage --consent-status # view your save decision / email / last send
|
|
232
|
+
shakers ai-usage --consent-revoke # revoke consent to save (-> denied), no more sends
|
|
233
|
+
shakers ai-usage --consent-reset # clear the decision (-> undecided), ask again next run
|
|
234
|
+
shakers ai-usage --consent-email E # change the email on file, without touching the decision
|
|
235
|
+
shakers ai-usage --set-endpoint URL # persist the ingest endpoint (see "Configuration" below)
|
|
236
|
+
shakers ai-usage --show-endpoint # show the effective endpoint and where it comes from
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
`ai-usage` no longer prints a report link — its output is the clean terminal
|
|
240
|
+
view. Use `report` to produce and open the full HTML (needs login):
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
shakers report # materialize + open this project's HTML report in the browser
|
|
244
|
+
shakers report --root ../other # report for another project
|
|
245
|
+
shakers report --no-open # just print the file:// link, don't launch the browser
|
|
246
|
+
shakers report --lang es|en # force the surrounding CLI copy + report language
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The `share` command reuses the last ai-usage stored for the project (needs login):
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
shakers share # build the LinkedIn card for this project's ai-usage
|
|
253
|
+
shakers share --root ../other # card for another project's ai-usage
|
|
254
|
+
shakers share --lang es|en # force the surrounding CLI copy language (the card is English)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Marketplace & profile
|
|
258
|
+
|
|
259
|
+
These talk to the Shakers platform on your behalf (they use your login session,
|
|
260
|
+
never a project scan). All need `shakers login` first.
|
|
261
|
+
|
|
262
|
+
**Chat with Alma.** Open an interactive mini-shell with your AI assistant from the
|
|
263
|
+
terminal. The conversation keeps its context across turns, and Alma can act on your
|
|
264
|
+
profile (with an arrow-key confirmation before anything irreversible):
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
shakers alma # opens the conversation; type "exit" to quit
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Before the first message, `alma` asks for **consent to share a code-free map of the
|
|
271
|
+
current project** (its name, services, agents, technologies — never your source
|
|
272
|
+
code) so Alma can answer with context. If you decline — or there is no terminal to
|
|
273
|
+
ask — every message is sent **without** that context. The consent is CLI-side only.
|
|
274
|
+
|
|
275
|
+
**Find and open projects.** `find-projects` lists the positions available to you,
|
|
276
|
+
ordered by match, paginated and filterable server-side:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
shakers find-projects # first page (grouped All / Saved)
|
|
280
|
+
shakers find-projects --page 2 --limit 20 # paginate
|
|
281
|
+
shakers find-projects --attendance remote --country ES # filter by work mode / country
|
|
282
|
+
shakers find-projects --tab saved # only your saved positions
|
|
283
|
+
shakers find-projects --json # machine output (includes ids)
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**Reference a project by its number.** `find-projects` and `applications` hide the
|
|
287
|
+
raw ids from the human listing and print a `N)` number instead. `show-project`,
|
|
288
|
+
`save-project` and `unsave-project` accept **that number** (from the last listing)
|
|
289
|
+
or a full id:
|
|
290
|
+
|
|
291
|
+
```bash
|
|
292
|
+
shakers show-project 3 # detail of item 3 from the last listing
|
|
293
|
+
shakers save-project 3 # bookmark item 3
|
|
294
|
+
shakers unsave-project 3 # remove the bookmark
|
|
295
|
+
shakers show-project <uuid> # a raw id also works (for scripts / --json)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Your applications and invitations:**
|
|
299
|
+
|
|
300
|
+
```bash
|
|
301
|
+
shakers applications # positions you applied to + status (also refreshes the number cache)
|
|
302
|
+
shakers invitations # your unread project invitations
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Your profile.** View by default; the two setters (`--set`) are interactive with
|
|
306
|
+
an explicit confirmation before writing (they change what clients see):
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
shakers me # summary: headline, role, % complete, rate, availability, languages, skills/agents count
|
|
310
|
+
shakers certifications # your role dimensions by state (certified / uncertified / expired) + band
|
|
311
|
+
shakers availability # view your availability (open-to-work, hours/month, location)
|
|
312
|
+
shakers availability --set # change it — arrow-key pickers, then confirm
|
|
313
|
+
shakers rate # view your per-project rate
|
|
314
|
+
shakers rate --set # change it — pick modality + currency, type the amount, then confirm
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
**Your roles.** A talent has one **MAIN role** plus optional **growth roles**. Both
|
|
318
|
+
commands use the same arrow-key picker as the rest of the CLI:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
shakers add-role # pick a role from the catalog and add it as a growth role
|
|
322
|
+
shakers change-role # switch your MAIN role to one you already have
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
`add-role` (alias `shakers role add`) reads the role catalog (the roles you do not
|
|
326
|
+
already hold) and adds the one you pick. `change-role` (alias `shakers role change`)
|
|
327
|
+
lists the roles you already hold and sets the one you pick as your MAIN role.
|
|
328
|
+
|
|
329
|
+
Setting your **MAIN role** is a step of **registration** (`shakers register`): after
|
|
330
|
+
you take or skip the interview during the alta, it offers your resolved/recommended
|
|
331
|
+
roles and lets you set your MAIN role. Running the interview on its own
|
|
332
|
+
(`shakers onboarding`) does **not** ask for the main role — to change it later use
|
|
333
|
+
`shakers change-role`.
|
|
334
|
+
|
|
335
|
+
**Repeat the onboarding interview.** `shakers onboarding --repeat` (alias
|
|
336
|
+
`shakers onboarding repeat`) re-runs the **interview only**, **overwriting** the
|
|
337
|
+
previous one (it does not touch your main role). Because the prior evaluation is
|
|
338
|
+
discarded and it cannot be undone, it first shows a clear warning and requires an
|
|
339
|
+
**explicit Yes/No confirmation** (arrow-key selector); on a non-TTY, pass `--yes` to
|
|
340
|
+
confirm. Only after you confirm does it reset the interview and run it again.
|
|
341
|
+
Declining aborts with no change. If you have no onboarding yet it tells you to run
|
|
342
|
+
`shakers onboarding` first.
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
shakers onboarding # the interview (+ final main-role step)
|
|
346
|
+
shakers onboarding --repeat # warn + confirm, then overwrite and re-run
|
|
347
|
+
shakers onboarding repeat --yes # same, pre-confirmed (non-interactive / agents)
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
Every listing/detail is also available as `--json` for scripting, and every
|
|
351
|
+
command takes `--lang es|en`.
|
|
352
|
+
|
|
353
|
+
Without installing, from a copy of the repo, `shakers <cmd>` is equivalent to
|
|
354
|
+
`node bin/shakers.js <cmd>`.
|
|
355
|
+
|
|
356
|
+
### Human vs. agent mode (dual TTY contract)
|
|
357
|
+
|
|
358
|
+
Every command keeps the same dual contract it had before the shell was
|
|
359
|
+
retired: on a real terminal it is **interactive** (prompts, masked secret
|
|
360
|
+
input, pickers); on a non-TTY (piped stdin, CI, an agent) it runs **one-shot**
|
|
361
|
+
and never blocks on a prompt it cannot answer. Each interactive question has a
|
|
362
|
+
flag equivalent (`--email`, `--root`, `--skill`, `--accept-disclaimer`,
|
|
363
|
+
`--consent-email`, …), read-heavy commands print machine-readable output with
|
|
364
|
+
`--json` (`ai-usage --json`), and **exit codes are meaningful** — a gated
|
|
365
|
+
command with no session, or a command that failed, exits non-zero, so an agent
|
|
366
|
+
can branch on the result.
|
|
367
|
+
|
|
368
|
+
Results are saved in `~/.config/shakers/` (a per-project cumulative HTML
|
|
369
|
+
report plus its `report-state.json`). **Nothing is ever written to the
|
|
370
|
+
scanned project** — the report can't slip into a commit by accident.
|
|
371
|
+
|
|
372
|
+
### MCP server (`shakers mcp`)
|
|
373
|
+
|
|
374
|
+
`shakers mcp` speaks JSON-RPC over stdio so a desktop AI app (Claude / ChatGPT
|
|
375
|
+
Desktop) can drive the same features as tools. It exposes, among others:
|
|
376
|
+
|
|
377
|
+
- **AI usage**: `ai_usage`, `ai_usage_result`.
|
|
378
|
+
- **Auth**: `login`, `logout`, `social_signin_start`, `social_signin_poll`.
|
|
379
|
+
- **Register / onboarding**: `register`, `register_status`,
|
|
380
|
+
`onboarding_interview_start`, `onboarding_interview_turn`,
|
|
381
|
+
`onboarding_interview_complete`, `repeat_onboarding_interview`
|
|
382
|
+
(OVERWRITE-repeat — the agent must warn the talent it is irreversible before
|
|
383
|
+
calling), `onboarding_finish`.
|
|
384
|
+
- **Roles**: `list_available_roles`, `add_role`, `list_my_roles`, `set_main_role`
|
|
385
|
+
— `set_main_role` is the onboarding **final step** (after
|
|
386
|
+
`onboarding_interview_complete`, or if the interview was skipped, offer
|
|
387
|
+
`list_my_roles` and set the picked one).
|
|
388
|
+
- **Profile / skills / agents**: `list_addable`, `add_skill`, `add_agent`,
|
|
389
|
+
`add_project`, `get_profile`, `get_rate`, `get_languages`, `list_socials`,
|
|
390
|
+
`list_experiences`, `list_portfolios`, `get_availability`.
|
|
391
|
+
- **Marketplace**: `find_projects`, `show_project`, `save_project`,
|
|
392
|
+
`unsave_project`, `list_invitations`, `list_applications`.
|
|
393
|
+
- **Certifications**: `list_certifications`, `list_certifiable_dimensions`.
|
|
394
|
+
- **Alma**: `ask`.
|
|
395
|
+
|
|
396
|
+
MCP tool names are **stable** (renaming would break existing client configs); the
|
|
397
|
+
role tools above were added, not renamed.
|
|
398
|
+
|
|
399
|
+
## Try it
|
|
400
|
+
|
|
401
|
+
Today the CLI runs from a repo checkout with `node bin/shakers.js` (the npm
|
|
402
|
+
package is `shakers`, run with `npx shakers <command>` — e.g. `npx shakers ai-usage` — which is later work). Verified commands:
|
|
403
|
+
|
|
404
|
+
```bash
|
|
405
|
+
node bin/shakers.js # no command → prints the usage help (exit 0)
|
|
406
|
+
node bin/shakers.js ai-usage # anonymous AI-usage evaluation (no session needed)
|
|
407
|
+
node bin/shakers.js ai-usage --help # the command's own flags/help
|
|
408
|
+
node bin/shakers.js login # sign in (needs an endpoint configured)
|
|
409
|
+
node bin/shakers.js logout # sign out (silent no-op if no session)
|
|
410
|
+
node bin/shakers.js certify # gated: with no session → clear error, exits 1
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Gating behaviour to expect, session-less: `ai-usage` and `login` run; `logout`
|
|
414
|
+
is a silent no-op (exit 0); `certify`/`report`/`share` print "requires an
|
|
415
|
+
active session" naming both `shakers login` and `shakers register`, and **exit
|
|
416
|
+
non-zero** (so an agent can branch on it). An unknown command (e.g. the removed `start`) also exits
|
|
417
|
+
non-zero.
|
|
418
|
+
|
|
419
|
+
## Skill certification (`certify`)
|
|
420
|
+
|
|
421
|
+
`certify` (run as `shakers certify`, alias `certify skills`) certifies
|
|
422
|
+
Skills from your Shakers catalog by analyzing your local project. **It
|
|
423
|
+
requires you to be [logged in](#login-login--logout) first** (ADR-050) — see
|
|
424
|
+
the login gate below; there is no email-only path any more. It runs in two
|
|
425
|
+
phases, back to back:
|
|
426
|
+
|
|
427
|
+
1. **Resolve** — detects your project technologies, asks the certifications
|
|
428
|
+
service which map to a Skill you can certify, and shows certifiable vs
|
|
429
|
+
non-certifiable. Only the detected **technology names** (plus an email
|
|
430
|
+
audit hint, when one is on file) leave the machine here — the call is
|
|
431
|
+
authenticated by your login session's bearer token, not by the email.
|
|
432
|
+
2. **Certify** — you pick ONE certifiable Skill to certify (interactive
|
|
433
|
+
single-select, or `--skill <name>` / `--skill <position>` non-interactively
|
|
434
|
+
— one Skill per run, so the mandatory interview below always has exactly
|
|
435
|
+
one Skill to interview about); the CLI takes a deterministic **code
|
|
436
|
+
sample** for it, runs a secret-scrub pass, sends it for a Skill assessment,
|
|
437
|
+
and shows the result. The assessment report is **always shown**; the
|
|
438
|
+
analyzed result is persisted to Shakers only if you granted consent up
|
|
439
|
+
front. Skill scores are **indicative and not reproducible** — not an
|
|
440
|
+
official qualification. This is the single most invasive payload in this
|
|
441
|
+
repo — your **actual sampled code** — so if you granted consent, it's also
|
|
442
|
+
the clearest case of what [Privacy & consent model](#privacy--consent-model)
|
|
443
|
+
describes as Datadog capture: a third party retaining that code for up to
|
|
444
|
+
three months, with no selective deletion afterwards. Right after the
|
|
445
|
+
code-only result, a short **interview about that same Skill** starts
|
|
446
|
+
automatically (see below) — it is no longer optional.
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
shakers certify # resolve + certify a Skill for the current project
|
|
450
|
+
shakers certify --root ../other # analyze another directory
|
|
451
|
+
shakers certify --skill React # certify the Skill by name (no interactive select)
|
|
452
|
+
shakers certify --skill 1 # certify the Skill at this position in the resolve report
|
|
453
|
+
shakers certify --email you@shakers.com
|
|
454
|
+
shakers certify --lang es|en
|
|
455
|
+
shakers certify --accept-disclaimer # accept the legal disclaimer non-interactively
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Unlike `ai-usage` (which always produces a local report), `certify` is
|
|
459
|
+
inherently server-side: it requires an endpoint — `SHAKERS_CLI_CERTIFY_ENDPOINT`,
|
|
460
|
+
or (its usual case) the resolved `SHAKERS_CLI_INGEST_ENDPOINT` from which the
|
|
461
|
+
certify route is derived as a sibling (see
|
|
462
|
+
[Configuration](#configuration-environment-variables)) — there is no
|
|
463
|
+
local-only certification and, since ADR-042, only ONE backend to configure. The
|
|
464
|
+
flow is deliberately front-loaded, and checked in this order, entirely before
|
|
465
|
+
any Skill is chosen: (1) the endpoint must be configured, (2) your project's
|
|
466
|
+
technologies are detected locally (no egress yet), (3) the **login gate**
|
|
467
|
+
refuses — with no egress at all — a run with no active session (a superadmin
|
|
468
|
+
session bypasses it, see [Superadmin](#superadmin-non-production-only)), (4) a
|
|
469
|
+
legal disclaimer is shown that you must explicitly accept (the code-egress
|
|
470
|
+
gate), and (5) — the first time, and skipped entirely for a logged-in Talent
|
|
471
|
+
whose session already carries an email — the save-to-Shakers consent and an
|
|
472
|
+
email OTP verification are handled, still before you choose a Skill. The
|
|
473
|
+
disclaimer assumes the project is your own and attributes responsibility to
|
|
474
|
+
you, so **never run it on a third party's code** (e.g. a client under NDA).
|
|
475
|
+
For local end-to-end testing, run the real certifications service and point
|
|
476
|
+
the endpoint at loopback (see "Local end-to-end testing" below); the in-repo
|
|
477
|
+
stub that used to serve this route is retired. The real implementation lives
|
|
478
|
+
in `sh-web-works-certifications` — the CLI's only backend.
|
|
479
|
+
|
|
480
|
+
### Skill interview — starts on its own, consent still required
|
|
481
|
+
|
|
482
|
+
Once `certify skills` shows the code-only assessment for the Skill you
|
|
483
|
+
certified, it goes straight into a short **interview about that same Skill**:
|
|
484
|
+
a few questions about the sampled code (an antifraud check) and about your
|
|
485
|
+
general command of the tool, over the same session/turn/verdict machine
|
|
486
|
+
`certify agents` uses. There is no "do you want to try it?" prompt any more —
|
|
487
|
+
it always reaches the interview when stdin is an interactive terminal and an
|
|
488
|
+
interview endpoint is configured. What it does NOT skip is consent: a legal
|
|
489
|
+
notice (what is asked, and what happens to your answers — including the
|
|
490
|
+
third-party Datadog retention if you gave content consent) is shown and you
|
|
491
|
+
must explicitly accept it before anything about the interview leaves the
|
|
492
|
+
machine; declining (or answering nothing) stops there, visibly, and your
|
|
493
|
+
code-only Skill certification is unaffected either way. Running from a
|
|
494
|
+
pipe/CI (no TTY) cannot host an interview or a consent answer, so it is
|
|
495
|
+
skipped with a visible message. The server combines the interview with the
|
|
496
|
+
code score into an attested combined level (Middle/Senior/Expert), which can
|
|
497
|
+
raise or lower what the code alone gave you.
|
|
498
|
+
|
|
499
|
+
### Agent certification (`certify agents`) — an interview, not a form
|
|
500
|
+
|
|
501
|
+
`certify agents` certifies how deeply you command ONE of your own agents
|
|
502
|
+
(`.claude/agents/*.md`). It is a real **interview**: the service opens a
|
|
503
|
+
session, asks **one question per turn**, decides which of the five assessment
|
|
504
|
+
areas each question probes, and decides when to stop. The CLI is the courier —
|
|
505
|
+
it re-sends the agent **definition** (never persisted server-side, only hashed)
|
|
506
|
+
and your answer, and it deliberately cannot choose the question or the area.
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
shakers certify agents # interview + verdict for one agent
|
|
510
|
+
shakers certify agents --root ../other
|
|
511
|
+
shakers certify agents --email you@shakers.com
|
|
512
|
+
shakers certify agents --lang es|en
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
What is worth knowing before you start:
|
|
516
|
+
|
|
517
|
+
- **Either the whole flow, or nothing is asked of you.** Certifying now needs
|
|
518
|
+
an **active [login](#login-login--logout) session** (ADR-050) — a session
|
|
519
|
+
proves control of the account, which is a higher bar than the
|
|
520
|
+
email+OTP check this used to be. That is checked **locally, before you are
|
|
521
|
+
asked for anything** — no address, no agent picker, no egress — and if
|
|
522
|
+
you're not logged in it stops right there with a distinct message for
|
|
523
|
+
"never logged in" vs "your session expired," and tells you to run `login`.
|
|
524
|
+
A non-production superadmin session bypasses this (see
|
|
525
|
+
[Superadmin](#superadmin-non-production-only)). `--email` (or the address
|
|
526
|
+
already on file) still travels as an optional audit hint the server matches
|
|
527
|
+
against your session — it is no longer what authenticates you. The
|
|
528
|
+
disclosure still comes first, because the login check itself sends nothing.
|
|
529
|
+
- **You can stop and come back.** Progress lives in
|
|
530
|
+
`~/.config/shakers/interview-session.json` (permissions `600`), written
|
|
531
|
+
atomically after every turn. If the process dies — Ctrl-C, a dropped
|
|
532
|
+
connection, a closed laptop — re-run `certify agents` and it offers to
|
|
533
|
+
continue where you left off, re-sending the answer that was in flight so you
|
|
534
|
+
never retype it. The file is deleted when the verdict arrives (or when the
|
|
535
|
+
session expires), and it holds a **bearer token** for your interview plus the
|
|
536
|
+
answer currently in flight, which is why it is `600` and why nothing prints
|
|
537
|
+
it.
|
|
538
|
+
- **There is a limit of 5 interviews per 24 hours**, and an abandoned session
|
|
539
|
+
still counts. That is why declining a resume tells you the attempt is already
|
|
540
|
+
spent, and why a transient network failure never silently opens a second
|
|
541
|
+
session.
|
|
542
|
+
- **Answers are capped at 4000 characters, counted after the secret-scrub
|
|
543
|
+
pass.** Scrubbing can make text *longer* (a path or a key becomes
|
|
544
|
+
`[REDACTED]`), so an answer that fits raw can be refused. You are told before
|
|
545
|
+
the first question, and an over-long answer is refused **locally**, with the
|
|
546
|
+
exact overshoot — never as a server error after you wrote three paragraphs.
|
|
547
|
+
- **You see the turn number and the areas you have been ASKED ABOUT, each with
|
|
548
|
+
how many turns it has had — not how many turns are left.** "Asked about" is not
|
|
549
|
+
"covered": whether an area is substantiated is the grader's judgement, and one
|
|
550
|
+
question is never it. The per-area count is there so a lopsided interview (five
|
|
551
|
+
turns on one area, one on another) is visible instead of invisible. The service
|
|
552
|
+
owns the stop condition; showing you its budget would turn "when does this end"
|
|
553
|
+
into something to play against.
|
|
554
|
+
- **Before the first question you are told what is being judged**: the reasoning
|
|
555
|
+
behind each decision, the alternatives you discarded and why, and concrete
|
|
556
|
+
cases where it showed. It is not a request for longer answers — a claim with no
|
|
557
|
+
reasoning behind it does not evidence command however long it is.
|
|
558
|
+
- **Two different lifetimes for what you write**, both stated in the disclosure
|
|
559
|
+
you accept before anything leaves: (1) inside Shakers your free text is
|
|
560
|
+
**deleted when the verdict is emitted**, in the same operation — only the
|
|
561
|
+
question, the quote that was verified and each area's tag survive; (2) if you
|
|
562
|
+
granted content consent, the copy at **Datadog LLM Observability** (a third
|
|
563
|
+
party) runs its full retention and **cannot be deleted** — the first deletion
|
|
564
|
+
does not reach it. And the asymmetry that matters: consent is read fresh on
|
|
565
|
+
every call, but if it is on for the **verdict** request, the **whole**
|
|
566
|
+
interview is captured, even if every earlier turn was sent without it.
|
|
567
|
+
- **The verdict can take minutes.** Grading runs three samples over the full
|
|
568
|
+
transcript, and it can outlast the CLI's own wait. When that happens the CLI
|
|
569
|
+
polls and collects the verdict rather than reporting a failure; if you give up
|
|
570
|
+
first, the session stays on disk and the next run picks the verdict up.
|
|
571
|
+
|
|
572
|
+
Like `certify skills`, this needs an endpoint: the four interview routes are
|
|
573
|
+
derived from `SHAKERS_CLI_INGEST_ENDPOINT`, the CLI's one backend (see
|
|
574
|
+
[Configuration](#configuration-environment-variables)).
|
|
575
|
+
|
|
576
|
+
## Login (`login` / `logout`)
|
|
577
|
+
|
|
578
|
+
A registered Talent identifies themselves with `login` (issue 122 / ADR-044).
|
|
579
|
+
Since ADR-061 a session is required by **every** command except `ai-usage` and
|
|
580
|
+
`login` itself — `certify` (both `skills` and `agents`) also proves control of
|
|
581
|
+
the **account**, not just of an email address (ADR-050). `login` and `logout`
|
|
582
|
+
run without a session (that is how you obtain/drop one); `logout` with no
|
|
583
|
+
session is a silent no-op.
|
|
584
|
+
|
|
585
|
+
```bash
|
|
586
|
+
shakers login # no method flag: interactive picker (Email / Google) on a real TTY
|
|
587
|
+
shakers login --email you@shakers.com # skip the picker, prompt only for the password
|
|
588
|
+
shakers login --google # skip the picker, go straight to the Google flow
|
|
589
|
+
shakers logout # forget the stored session (no-op if none)
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
- **No `--password` flag, ever.** `argv` is visible to every other process on
|
|
593
|
+
the machine (`ps`) and lands in shell history, so the password is only ever
|
|
594
|
+
collected via a masked interactive prompt or a stdin pipe — never a flag.
|
|
595
|
+
- **Email/password** sends `{ email, password }` to the certifications
|
|
596
|
+
service's `POST /api/v1/auth/login/email`, which proxies the credentials to
|
|
597
|
+
the Shakers Hub **server-side** and runs its token-exchange, returning a
|
|
598
|
+
certifications-service JWT the CLI stores locally. The password transits
|
|
599
|
+
CLI → certifications service → Hub, over TLS, and is never persisted by the
|
|
600
|
+
certifications service.
|
|
601
|
+
- **Google** is an **OAuth 2.0 Device Authorization Grant** (RFC 8628): the CLI
|
|
602
|
+
asks the Hub for a short code, shows you a URL and a `XXXX-XXXX` code to enter
|
|
603
|
+
in your browser, and polls until you authorize. Nothing about Google lives on
|
|
604
|
+
your machine — no client id, no loopback server, no secret; the Hub owns all
|
|
605
|
+
Google config and does the token exchange server-side. After you authorize, the
|
|
606
|
+
Hub session is exchanged for the same API JWT the email flow stores.
|
|
607
|
+
- **LinkedIn is parked** (ADR-041/046) — not implemented.
|
|
608
|
+
- The session (`{ accessToken, expiresAt, email }`) is stored **atomically**,
|
|
609
|
+
permissions `600`, in `~/.config/shakers/auth-session.json`. **Logged in**
|
|
610
|
+
means "an unexpired token is present" — an unparseable or missing
|
|
611
|
+
`expiresAt` is treated as expired, never as active. `login` while a session
|
|
612
|
+
is already active tells you so instead of silently overwriting it; run
|
|
613
|
+
`logout` first to switch accounts.
|
|
614
|
+
|
|
615
|
+
## Superadmin (non-production only)
|
|
616
|
+
|
|
617
|
+
`superadmin` is a password-gated, **non-production** test tool for the team
|
|
618
|
+
running this CLI against a service instance — not something a Talent uses.
|
|
619
|
+
The server 404s every superadmin route in production regardless of the
|
|
620
|
+
password.
|
|
621
|
+
|
|
622
|
+
```bash
|
|
623
|
+
shakers superadmin # open a session (prompts password + your own email)
|
|
624
|
+
shakers superadmin --email you@shakers.com # same, prompts only the password
|
|
625
|
+
shakers superadmin --inspect --email talent@example.com # read-only certification receipt (ADR-025)
|
|
626
|
+
shakers superadmin --logout # forget the locally stored session
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
- **Also no `--password` flag**, for the same reason as `login` — the
|
|
630
|
+
password is only ever read from an interactive prompt or a stdin pipe.
|
|
631
|
+
- Opening a session validates the password server-side and persists the
|
|
632
|
+
returned token locally (`config.json`'s `superadminSession`, ADR-027).
|
|
633
|
+
`certify` then accepts that session **instead of** a `login` session,
|
|
634
|
+
bypassing the login/identity gates on **any** email/repo, and its results
|
|
635
|
+
are stamped `test_origin: true`.
|
|
636
|
+
- **A known, documented exception (ADR-050):** unlike `certify agents`
|
|
637
|
+
(hardened to reject an unregistered email), the skill-code certification's
|
|
638
|
+
superadmin branch still tolerates `userId: null` and lets a superadmin
|
|
639
|
+
certify code against an unregistered email. This asymmetry is deliberate
|
|
640
|
+
and left as-is — it's non-production, encrypted, and yields no durable
|
|
641
|
+
credential — not a bug to fix to parity.
|
|
642
|
+
- `--inspect` is read-only: it prints the stored authorship + rubric evidence
|
|
643
|
+
for an email's certifications (an attribution trail, not cryptographic
|
|
644
|
+
proof).
|
|
645
|
+
|
|
646
|
+
## The report
|
|
647
|
+
|
|
648
|
+
- **Terminal output** (from `ai-usage`/`certify`) and a **self-contained HTML
|
|
649
|
+
dashboard** (opened by `report`; Shakers branding, responsive, zero network
|
|
650
|
+
calls — no CDN, no external script, no fetch). The terminal is the concise
|
|
651
|
+
view; the HTML carries the full detail.
|
|
652
|
+
- **`ai-usage`/`certify` persist their result silently** into
|
|
653
|
+
`report-state.json` and print **no** link (ADR-016). The HTML is produced and
|
|
654
|
+
opened only when you run **`report`** — which regenerates the per-project HTML
|
|
655
|
+
from state, opens it in your browser (use `--no-open` to just print the link),
|
|
656
|
+
and prints the clickable `file://` link.
|
|
657
|
+
- **Localized to your OS locale**: a locale starting with `es` shows
|
|
658
|
+
Spanish; anything else shows English (`src/locale.js` / `src/i18n.js`).
|
|
659
|
+
`--lang` overrides this for a single run, including the copyable
|
|
660
|
+
implementation prompt.
|
|
661
|
+
- **Terminal sections (ADR-016), in order**: the "why this tier" analysis
|
|
662
|
+
FIRST, then the score meter, detected tools, technologies, and a
|
|
663
|
+
one-line-per-agent summary (name + model + definition-quality score + local
|
|
664
|
+
usage, with `↓` nesting). No environment section; the roadmap / next-steps is
|
|
665
|
+
behind `--roadmap`.
|
|
666
|
+
- **HTML sections**: everything above at full length, plus the environment,
|
|
667
|
+
MCP servers, the agent org chart with **per-agent detail** (score, rationale,
|
|
668
|
+
usage), and the current→next roadmap with its implementation prompt.
|
|
669
|
+
- **The HTML report is cumulative and scoped per project.** Each scanned
|
|
670
|
+
project has its OWN report file (`report-<hash>.html` in
|
|
671
|
+
`~/.config/shakers/`), keyed by the project's absolute path, and is
|
|
672
|
+
regenerated whole from `report-state.json` each time you run `report`. It
|
|
673
|
+
fills in over time: the usage section appears once you've run `ai-usage`
|
|
674
|
+
in that project, and the certification section once you've run `certify`
|
|
675
|
+
there; both appear together when both have run for the **same** project. This is
|
|
676
|
+
intentional (skill-code-certification, reporting redesign) — the report is a
|
|
677
|
+
persistent per-project artifact, not a per-invocation transcript. So running
|
|
678
|
+
`certify` in a project where you previously ran `ai-usage` correctly
|
|
679
|
+
still shows the usage section: that usage was produced for this
|
|
680
|
+
project and is part of its cumulative record, not stale or leaked data.
|
|
681
|
+
Different projects never mix into one document.
|
|
682
|
+
- **Score scope (ADR-010, reverts ADR-009): the 0-100 score is computed over
|
|
683
|
+
project ∪ home** — your whole developer AI setup (the project's signals plus
|
|
684
|
+
your global `~/.claude` and machine-level config), not this one project in
|
|
685
|
+
isolation. It measures the maturity of _you as a developer_, so projects that
|
|
686
|
+
share a home tend to read similar scores. ADR-009 had briefly scoped the score
|
|
687
|
+
to the project directory only, but that drove notes too low (project-level AI
|
|
688
|
+
config is sparse), so ADR-010 reverted it to the earlier project ∪ home
|
|
689
|
+
behaviour. The **tier (T0-T7)** uses the same project ∪ home scope.
|
|
690
|
+
|
|
691
|
+
## What it detects
|
|
692
|
+
|
|
693
|
+
All detection is **deterministic** (no LLM) and reads only known AI-tool
|
|
694
|
+
configuration — never your project's business logic or source code:
|
|
695
|
+
|
|
696
|
+
- **Tools**: Claude Code, Cursor, GitHub Copilot, Windsurf, Aider,
|
|
697
|
+
Continue, Cline, Gemini CLI, Codex CLI, Amazon Q Developer, Cody, Zed,
|
|
698
|
+
Tabnine — existence of config files/directories, binaries on `PATH`,
|
|
699
|
+
installed editor extensions.
|
|
700
|
+
- **Depth per tool**: project instructions/rules, MCP servers configured,
|
|
701
|
+
own skills/commands, hooks.
|
|
702
|
+
- **MCP servers**: names and a heuristic category (data/comms/dev/browser/
|
|
703
|
+
other) from known config locations (`.mcp.json`, `.cursor/mcp.json`,
|
|
704
|
+
Windsurf/Gemini config, etc.) — only the top-level server-name keys are
|
|
705
|
+
read, never the values (which can carry commands, URLs or env vars).
|
|
706
|
+
- **Memory structure**: `@file` import count and nesting depth, section
|
|
707
|
+
count and byte size of context files (`CLAUDE.md`, `AGENTS.md`,
|
|
708
|
+
`GEMINI.md`) — structure only, never the file's actual text is stored.
|
|
709
|
+
- **Automations**: npm/shell scripts that invoke a known AI CLI, JSON-piping
|
|
710
|
+
patterns, and scheduled tasks (cron/launchd/pm2/systemd) — counts and
|
|
711
|
+
booleans only.
|
|
712
|
+
- **Browser tools**: Playwright/Puppeteer as a project dependency, or a
|
|
713
|
+
browser-category MCP server.
|
|
714
|
+
- **Agents**: your `.claude/agents/*.md` org chart (name, wired tools,
|
|
715
|
+
model, hierarchy) — deterministic; an optional server-side LLM step can
|
|
716
|
+
synthesize a short description per agent for nicer cards (see below).
|
|
717
|
+
- **Technologies**: frameworks/libraries actually used in the project
|
|
718
|
+
(React, Next.js, Express, Django...), parsed from dependency manifests
|
|
719
|
+
(`package.json`, `requirements.txt`, `go.mod`, etc.) and filtered through
|
|
720
|
+
a curated name map — never a raw dependency dump.
|
|
721
|
+
- **Hooks**: hook-based automation configured for a tool.
|
|
722
|
+
|
|
723
|
+
**Never** read, stored or sent: file _contents_ beyond what's needed to
|
|
724
|
+
compute a count, absolute paths, environment variables, or credentials.
|
|
725
|
+
|
|
726
|
+
## Tier ladder (T0-T7)
|
|
727
|
+
|
|
728
|
+
The tier is "the highest tier whose criteria you ALL meet, checked strictly
|
|
729
|
+
bottom-up". The 0-4 band used elsewhere (e.g. Shakers direction views) is
|
|
730
|
+
derived from the tier — the tier is the single source of truth.
|
|
731
|
+
|
|
732
|
+
| Tier | Name | Criterion |
|
|
733
|
+
| ---- | --------------------- | -------------------------------------------- |
|
|
734
|
+
| T0 | Empty bench | no tool detected |
|
|
735
|
+
| T1 | First tool | at least one tool detected |
|
|
736
|
+
| T2 | Bench with notes | T1 + project instructions/rules/config exist |
|
|
737
|
+
| T3 | Connected bench | T2 + at least one MCP server configured |
|
|
738
|
+
| T4 | Own tooling | T3 + own skills/commands/rules |
|
|
739
|
+
| T5 | Agentic operator | agentic CLI + MCP + own tooling together |
|
|
740
|
+
| T6 | Multi-agent | T5 + 2 or more agents defined |
|
|
741
|
+
| T7 | Orchestrated workshop | T6 + at least one hook configured |
|
|
742
|
+
|
|
743
|
+
File recency (`mtime`) is informative only — it is never a gating signal
|
|
744
|
+
for any tier.
|
|
745
|
+
|
|
746
|
+
## Optional server-side LLM layers
|
|
747
|
+
|
|
748
|
+
Three capabilities are ephemeral, optional, server-side LLM calls — all run
|
|
749
|
+
independently of the save/consent decision (they never touch the
|
|
750
|
+
persistence payload) and all degrade gracefully (deterministic fallback, or
|
|
751
|
+
simply no scores shown) if the endpoint is unset or the call fails for any
|
|
752
|
+
other reason. Since ADR-042 there is a single backend to answer any of
|
|
753
|
+
them — no second hop to retry against.
|
|
754
|
+
|
|
755
|
+
"Ephemeral" here is about the SHAKERS-side persistence payload only — it does
|
|
756
|
+
**not** mean the call's content is never stored anywhere. See
|
|
757
|
+
[Privacy & consent model](#privacy--consent-model) for what a `granted`
|
|
758
|
+
consent additionally authorizes a third-party observability provider to
|
|
759
|
+
capture.
|
|
760
|
+
|
|
761
|
+
- **Agent-card synthesis** (`SHAKERS_CLI_SYNTHESIS_ENDPOINT`): sends your
|
|
762
|
+
agents' description text to synthesize a short symbolic name + "what it
|
|
763
|
+
does" per agent, for nicer cards. Falls back to the deterministic org
|
|
764
|
+
chart if unavailable — and, per agent, to your own raw `.claude/agents/`
|
|
765
|
+
description (cleaned up and excerpted for card display) or a minimal
|
|
766
|
+
name-derived line if that's missing too, so a card's description is
|
|
767
|
+
never blank.
|
|
768
|
+
- **Roadmap personalization** (`SHAKERS_CLI_ROADMAP_ENDPOINT`): asks the
|
|
769
|
+
certifications service to rewrite the current tier jump's prose (what it unlocks, steps,
|
|
770
|
+
tips, mistakes) adapted to your detected stack. The tier, the band, and
|
|
771
|
+
the "when to upgrade" criterion are **never** touched by this call — only
|
|
772
|
+
the curated roadmap's fallback prose can ever change. Only derived
|
|
773
|
+
signals are sent (frameworks, tool/MCP categories, tier), never raw file
|
|
774
|
+
content or agent descriptions.
|
|
775
|
+
- **Agent definition-quality evaluation** (`agent-evaluation`, derived as a
|
|
776
|
+
sibling of your ingest endpoint; overridable with
|
|
777
|
+
`SHAKERS_CLI_AGENT_EVAL_ENDPOINT`): sends the scrubbed agent definitions and
|
|
778
|
+
gets back a 0-100 score + short rationale per agent (**gemini-2.5-flash**
|
|
779
|
+
server-side, prompt version `agent-eval-v1`). The definition is treated as
|
|
780
|
+
DATA server-side (prompt-injection safe). Degradation is by omission — the
|
|
781
|
+
server drops any agent it couldn't score, and agents with no returned score
|
|
782
|
+
render without a number. No endpoint / failure → no scores shown.
|
|
783
|
+
|
|
784
|
+
All three send only derived signals or scrubbed agent definitions — never raw
|
|
785
|
+
file content — and a scrub pass runs before anything leaves the machine.
|
|
786
|
+
|
|
787
|
+
Separately, `ai-usage` reads your **local Claude Code history**
|
|
788
|
+
(`~/.claude/projects/**`) to count how often each detected agent was actually
|
|
789
|
+
invoked on this machine. This is **usage only**: it extracts a single signal per
|
|
790
|
+
line — the `subagent_type` of an `Agent` tool call — and never reads, stores, or
|
|
791
|
+
transmits prompt text, tool inputs, or any session content. The counts stay
|
|
792
|
+
strictly local (not in the persistence payload). It degrades gracefully if the
|
|
793
|
+
history directory is absent or unreadable.
|
|
794
|
+
|
|
795
|
+
## Privacy & consent model
|
|
796
|
+
|
|
797
|
+
- **The CLI talks to ONE Shakers backend.** Every call this tool makes — the
|
|
798
|
+
usage send, the optional LLM layers above, `login`, and everything under
|
|
799
|
+
`certify` (resolve, certify, email verification, agent certification,
|
|
800
|
+
skill interview) — goes to a single configured endpoint,
|
|
801
|
+
`sh-web-works-certifications`. Until 2026-08-04 (ADR-021) there was a
|
|
802
|
+
second hop that fell back to `shakers-hub-backend`; ADR-042 retired it once
|
|
803
|
+
it was confirmed that hop never had the routes mounted (it only ever
|
|
804
|
+
answered 404, which had already masked at least one real timeout in a
|
|
805
|
+
diagnosis). There is no fallback any more: an unset or unreachable endpoint
|
|
806
|
+
is a real, named error (timeout / connection refused / 5xx), not a silent
|
|
807
|
+
hop to somewhere else. Nothing is deployed at a real address yet — see
|
|
808
|
+
[Configuration](#configuration-environment-variables) — and `install.sh`
|
|
809
|
+
writes a loopback placeholder by default, so a fresh, unconfigured install
|
|
810
|
+
talks to nothing on the Talent's own machine.
|
|
811
|
+
- **The report is always generated and shown locally, unconditionally.**
|
|
812
|
+
There is no gate, no wall, no preview step before you see your own data.
|
|
813
|
+
- **Saving (persisting) it to Shakers is opt-in, asked once.** The first
|
|
814
|
+
time you run the tool, right **after** the report is already on screen,
|
|
815
|
+
you're asked a short yes/no question: do you want this report saved in
|
|
816
|
+
Shakers? Accepting asks for an email; declining persists that choice and
|
|
817
|
+
you're never asked again. Manage the decision any time with
|
|
818
|
+
`--consent-status` / `--consent-revoke` / `--consent-email`, without
|
|
819
|
+
re-running the scan.
|
|
820
|
+
- **This one yes/no now governs TWO different things (talents-ai-score,
|
|
821
|
+
ADR-028), kept explicit rather than blurred into one vague permission —
|
|
822
|
+
there is no separate flag for each yet, it's a single consent:**
|
|
823
|
+
1. **Persisting in Shakers.** Only derived signals are ever sent for
|
|
824
|
+
saving — booleans, counts, categories, tier/band, the detected
|
|
825
|
+
technology names, and (if it ran) the synthesized agent summaries.
|
|
826
|
+
**Never** file contents, absolute paths, environment variables, or
|
|
827
|
+
credentials. The email you typed travels outside this whitelisted
|
|
828
|
+
payload, in the request body.
|
|
829
|
+
2. **Capturing content in a third-party observability provider.**
|
|
830
|
+
`ai-usage`/`certify`'s optional server-side AI calls — agent-card
|
|
831
|
+
synthesis, roadmap personalization, agent definition-quality
|
|
832
|
+
evaluation, CERTIFY's skill-code
|
|
833
|
+
assessment, and every call of the agent-certification **interview**
|
|
834
|
+
(each turn, plus the verdict) — send a
|
|
835
|
+
`traceContentConsent` flag reflecting your **current**, per-request
|
|
836
|
+
decision. When (and only when) it's `true`, **Datadog LLM
|
|
837
|
+
Observability**, a company **other than Shakers**, may capture and
|
|
838
|
+
retain the prompt/output of that call — which, for CERTIFY and agent
|
|
839
|
+
certification, includes your **actual sampled source code** and your
|
|
840
|
+
**free-text answers**, not just derived signals. Retention is up to
|
|
841
|
+
**three months**, configured on Datadog's side. **There is no promise
|
|
842
|
+
of later, per-item deletion of that content** — unlike the structured
|
|
843
|
+
payload above (governed by `--consent-revoke`/purge), Datadog's
|
|
844
|
+
retention is the only expiry that exists for it. If you decline (or
|
|
845
|
+
never decide), nothing is sent there — this is the safe default; the
|
|
846
|
+
flag is only ever omitted or `true`, never inferred.
|
|
847
|
+
- **The optional LLM layers above still run REGARDLESS of your save
|
|
848
|
+
decision** — that's what makes the diagram, the roadmap and the agent
|
|
849
|
+
scores "always show". What changes with consent is ONLY whether Datadog
|
|
850
|
+
may capture what they send, per point 2 above; the call itself, and
|
|
851
|
+
whether it's silently dropped or degraded on failure, is unaffected by
|
|
852
|
+
consent either way. The local **usage** read (Claude Code history) is not
|
|
853
|
+
even a network call — it never leaves the machine, consent or not.
|
|
854
|
+
- The consent decision lives in `~/.config/shakers/consent.json`
|
|
855
|
+
(permissions `600`).
|
|
856
|
+
- An **unfinished interview** (agent certification, or the skill-code
|
|
857
|
+
interview under `certify skills`) lives in
|
|
858
|
+
`~/.config/shakers/interview-session.json` (permissions `600`, written
|
|
859
|
+
atomically — the two kinds share one file, discriminated by a `kind`
|
|
860
|
+
field). It holds a bearer token for that interview and the answer
|
|
861
|
+
currently in flight — nothing else of what you typed — and it is deleted as
|
|
862
|
+
soon as the verdict arrives or the session expires. Delete it by hand at any
|
|
863
|
+
time: the only consequence is losing the ability to resume that interview
|
|
864
|
+
(the attempt it spent is already counted server-side either way).
|
|
865
|
+
- A **login session** lives in `~/.config/shakers/auth-session.json`
|
|
866
|
+
(permissions `600`, written atomically): the bearer token that identifies
|
|
867
|
+
you to `certify`, plus its expiry and (when the server sent one) your
|
|
868
|
+
email. See [Login](#login-login--logout).
|
|
869
|
+
- **Legal**: sending data about how a person works involves personal-data
|
|
870
|
+
processing (GDPR). This model has legal/labor sign-off reported for the
|
|
871
|
+
current design (see `active-work/talents-ai-score/decisions.md`,
|
|
872
|
+
ADR-011/013). **Activating sending against real Shakers talents in
|
|
873
|
+
production is a separate deployment decision that still requires its own
|
|
874
|
+
legal/labor go-ahead** for that rollout — this repo doesn't ship a
|
|
875
|
+
production endpoint by default (see below).
|
|
876
|
+
- **Legal copy across FOUR separate disclosure texts** (reviewed — the
|
|
877
|
+
`[PENDING LEGAL/LABOR REVIEW — NOT FINAL]` markers were removed), each shown
|
|
878
|
+
before a different kind of egress: the save-to-Shakers consent intro
|
|
879
|
+
(`ai-usage` / `certify skills`), the `certify skills` code-egress disclaimer,
|
|
880
|
+
the `certify agents` interview disclaimer, and the `certify skills` interview
|
|
881
|
+
disclaimer. All four state that **you are solely responsible for owning/being
|
|
882
|
+
authorized to analyze the code you submit, that Shakers assumes no liability
|
|
883
|
+
for it, and that misuse may lead to penalties on your Shakers account (up to
|
|
884
|
+
suspension)**. The skill-interview disclosure additionally names, per
|
|
885
|
+
ADR-049, that the interview asks questions **about the code you just
|
|
886
|
+
sampled**. And per ADR-051, that disclosure's own yes/no is a **real consent
|
|
887
|
+
gate**, not decorative text: declining it skips the interview outright (your
|
|
888
|
+
code-only Skill certification stands either way) — only the earlier "do you
|
|
889
|
+
want to try the interview?" opt-in was removed, not this consent.
|
|
890
|
+
|
|
891
|
+
## Configuration (environment variables)
|
|
892
|
+
|
|
893
|
+
The backend endpoints ARE baked in, per flavor, in `ENV_PROFILES`
|
|
894
|
+
(`src/config.js`): `staging`, `dev` and `local`. The default flavor is derived
|
|
895
|
+
from the package `name` (`shakers-cli-beta` → staging, `@shakers/shakers-cli` →
|
|
896
|
+
dev), forceable with `SHAKERS_CLI_ENV=staging|dev|local` — see
|
|
897
|
+
[Publishing](#publishing-maintainers) above. No secret is ever compiled in
|
|
898
|
+
(ADR-002/007). The baked profile is only a DEFAULT: the per-endpoint
|
|
899
|
+
`SHAKERS_CLI_*_BASE` env vars and `config.json` always win over it (env >
|
|
900
|
+
`config.json` > baked profile), and the profile bases reach the getters by
|
|
901
|
+
seeding a fresh `config.json` on first run. Every code path that depends on an
|
|
902
|
+
endpoint either degrades gracefully (no send / deterministic fallback) or — for
|
|
903
|
+
`certify`, which has no local-only product — surfaces an actionable error;
|
|
904
|
+
neither ever breaks the local `ai-usage` report.
|
|
905
|
+
|
|
906
|
+
**Since ADR-042 the CLI talks to ONE backend**, `sh-web-works-certifications`.
|
|
907
|
+
The two-hop chain this section used to describe (a `shakers-hub-backend`
|
|
908
|
+
fallback) is retired: it never had the routes mounted on `develop`, so every
|
|
909
|
+
"fallback" was an instant 404 that once masked a real timeout in a
|
|
910
|
+
diagnosis. Only ONE variable needs setting; everything else this CLI calls is
|
|
911
|
+
**derived from it** as a sibling route (`deriveFromIngest` in `src/config.js`)
|
|
912
|
+
— the base path's last segment (e.g. `.../usage/reports`) is swapped for the
|
|
913
|
+
sibling's (e.g. `.../usage/skill-certification/sessions`).
|
|
914
|
+
|
|
915
|
+
| Variable | Purpose |
|
|
916
|
+
| -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
917
|
+
| `SHAKERS_CLI_INGEST_ENDPOINT` | **The one endpoint to configure.** Where a saved `usage` report is sent (if consent is granted). Every other endpoint below derives from it unless it has its own override. |
|
|
918
|
+
| `SHAKERS_CLI_CERTIFY_ENDPOINT` | Override for the `certify` skill-certification route. Unset derives from ingest. Unlike `usage`'s endpoints, a missing one here is an **actionable error**, never a silent no-op — `certify` has no local-only product. |
|
|
919
|
+
| `SHAKERS_CLI_LOGIN_ENDPOINT` | Override for `login`'s email/password route. Unset derives from ingest (climbing out of the `usage` module: `.../api/v1/auth/login/email`). |
|
|
920
|
+
| `SHAKERS_CLI_DEVICE_AUTHORIZE_ENDPOINT`| Override for Google device-flow authorize (`POST .../auth/device/code`). Unset derives from the hub base. |
|
|
921
|
+
| `SHAKERS_CLI_DEVICE_TOKEN_ENDPOINT` | Override for Google device-flow token polling (`POST .../works/auth/device/token`). Unset derives from the hub base. |
|
|
922
|
+
| `SHAKERS_CLI_SYNTHESIS_ENDPOINT` | Override for agent-card synthesis (optional feature). Unset derives from ingest. |
|
|
923
|
+
| `SHAKERS_CLI_ROADMAP_ENDPOINT` | Override for roadmap personalization (optional feature). Unset derives from ingest. |
|
|
924
|
+
| `SHAKERS_CLI_AGENT_EVAL_ENDPOINT` | Override for agent definition-quality evaluation (optional feature). Unset derives from ingest. |
|
|
925
|
+
| `SHAKERS_CLI_CONFIG_DIR` | Override `~/.config/shakers/` (mainly for tests). |
|
|
926
|
+
|
|
927
|
+
> **Env prefix (ADR-045):** the CLI's variables use the `SHAKERS_CLI_*` prefix
|
|
928
|
+
> (distinct from the certifications backend's own `SHAKERS_*`). The pre-rename
|
|
929
|
+
> `AI_FOOTPRINT_*` names are still honoured as a fallback — if the new name is
|
|
930
|
+
> unset and the old one is set, the old one is used — so nothing breaks for
|
|
931
|
+
> anyone who exported the old variables.
|
|
932
|
+
|
|
933
|
+
Every other endpoint this CLI calls (email verification request/verify,
|
|
934
|
+
agent-certification interview sessions, skill-certification interview
|
|
935
|
+
sessions, and the two superadmin routes) has **no** env-var override at all —
|
|
936
|
+
they are always derived from ingest; see `src/config.js` for the full list of
|
|
937
|
+
`get*Endpoint` getters. The agent-certification and skill-interview session
|
|
938
|
+
bases are derived exactly like the others, but their **per-session** URLs
|
|
939
|
+
(`/:id`, `/:id/turns`, `/:id/verdict`) are built by string concatenation in
|
|
940
|
+
the client, never re-derived (`deriveFromIngest` replaces the base's last
|
|
941
|
+
path segment, and that base already ends in `sessions`).
|
|
942
|
+
|
|
943
|
+
### Config file (persistent ingest endpoint)
|
|
944
|
+
|
|
945
|
+
So you don't have to `export SHAKERS_CLI_INGEST_ENDPOINT` every session, it
|
|
946
|
+
can also live in a persistent file next to consent/reports:
|
|
947
|
+
|
|
948
|
+
```
|
|
949
|
+
~/.config/shakers/config.json
|
|
950
|
+
{
|
|
951
|
+
"ingestEndpoint": "https://your-certifications-service/api/v1/usage/reports"
|
|
952
|
+
}
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
Set it without editing JSON by hand:
|
|
956
|
+
|
|
957
|
+
```bash
|
|
958
|
+
shakers ai-usage --set-endpoint https://your-certifications-service/api/v1/usage/reports
|
|
959
|
+
shakers ai-usage --show-endpoint # prints the effective endpoint and its source
|
|
960
|
+
```
|
|
961
|
+
|
|
962
|
+
**Resolution precedence:** `SHAKERS_CLI_INGEST_ENDPOINT` (env var, the raw
|
|
963
|
+
developer override, legacy `AI_FOOTPRINT_INGEST_ENDPOINT` honoured too) **>**
|
|
964
|
+
`config.json` **>** none. There is still no compiled-in production default in
|
|
965
|
+
the code — only `install.sh` bakes a loopback placeholder into a FRESH config
|
|
966
|
+
file (see the prominent comment there; **this must change before real
|
|
967
|
+
distribution**). Every sibling-derived endpoint in the table above keeps
|
|
968
|
+
deriving from whichever value this resolves to.
|
|
969
|
+
|
|
970
|
+
**A config file written before ADR-042 may still carry the retired
|
|
971
|
+
`ingestEndpointFallback` key.** `install.sh` never overwrites an existing
|
|
972
|
+
`config.json`, so upgrading doesn't clean it up. The policy is deliberate:
|
|
973
|
+
the key is **ignored** (nothing reads it any more), **never migrated** (there
|
|
974
|
+
is nowhere to migrate a hub URL to — the one endpoint is already configured
|
|
975
|
+
separately) and **never erased** (this CLI never rewrites a Talent's config
|
|
976
|
+
file except behind an explicit `--set-*`, and a rewrite is the one operation
|
|
977
|
+
that could lose it). `--show-endpoint` is the one place that says the key is
|
|
978
|
+
present and unused, so nobody debugging their setup mistakes it for a live
|
|
979
|
+
hop.
|
|
980
|
+
|
|
981
|
+
**Endpoint safety (bounded):** because the endpoint decides where the sampled
|
|
982
|
+
code (`certify`) and derived signals (`ai-usage`) are sent, `--set-endpoint`
|
|
983
|
+
refuses to persist an `http://` URL to any host other than
|
|
984
|
+
`localhost`/`127.0.0.1`/`::1` — a non-local host must be `https`. There is no
|
|
985
|
+
domain allowlist yet (`SHAKERS_CLI_DOMAINS` in `src/config.js` is deliberately
|
|
986
|
+
empty — see that file's docblock for why an unverified entry would be worse
|
|
987
|
+
than none); a non-loopback, non-allowlisted host still requires you to type
|
|
988
|
+
the hostname back before `--set-endpoint` persists it. The env var is not
|
|
989
|
+
validated (it's the explicit developer escape hatch); a hand-edited config
|
|
990
|
+
file carrying an insecure remote endpoint is ignored at read time.
|
|
991
|
+
|
|
992
|
+
## Local end-to-end testing
|
|
993
|
+
|
|
994
|
+
**Run the real backend and point the CLI at loopback.** There used to be a
|
|
995
|
+
`reference-server/` stub in this repo that you could run instead; it is
|
|
996
|
+
**retired** (talents-ai-score, issue 044) and it is not coming back. It still
|
|
997
|
+
answered the `agent-certification/followups` and `/verdict` routes after those
|
|
998
|
+
were retired from the service, and it never had a single **interview** route, so
|
|
999
|
+
anyone who ran it was testing against a contract that no longer exists. That is
|
|
1000
|
+
worse than having no stub: it fails silently and in your favour.
|
|
1001
|
+
|
|
1002
|
+
It was retired rather than repaired on purpose. Serving the agent-certification
|
|
1003
|
+
interview would mean reimplementing session state, the `seq` cursor, per-turn
|
|
1004
|
+
idempotency, the stop condition and evidence anchoring — a second implementation
|
|
1005
|
+
of the most delicate semantics in the system, which would lie to your face the
|
|
1006
|
+
moment it drifted from the real one. Running the real service is what the team
|
|
1007
|
+
does, and it is the only way to get answers you can trust.
|
|
1008
|
+
|
|
1009
|
+
This also settles a standing caveat: the old stub kept its reports in an
|
|
1010
|
+
in-memory map, so every mention of it had to warn that production demands a real
|
|
1011
|
+
database. That warning is **obsolete by retirement, not by oversight** — there is
|
|
1012
|
+
no in-repo server left that anyone could mistake for the real one. Persistence is
|
|
1013
|
+
the certifications service's business (Prisma/Postgres), and always was.
|
|
1014
|
+
|
|
1015
|
+
The backend is the Shakers certifications service
|
|
1016
|
+
(NestJS + Prisma + Postgres) — since ADR-042, the CLI's **only** backend.
|
|
1017
|
+
Its `usage` module mounts every route this CLI calls (plus `auth/login/*`)
|
|
1018
|
+
under the service's `api/v1` global prefix. Start it in its own checkout (it
|
|
1019
|
+
needs its own database and secrets — see that repo's README), then:
|
|
1020
|
+
|
|
1021
|
+
```bash
|
|
1022
|
+
# the service listens on PORT, default 3000, with global prefix /api/v1
|
|
1023
|
+
export SHAKERS_CLI_INGEST_ENDPOINT=http://127.0.0.1:3000/api/v1/usage/reports
|
|
1024
|
+
shakers ai-usage
|
|
1025
|
+
```
|
|
1026
|
+
|
|
1027
|
+
`http://` is accepted **only** for loopback (`localhost`, `127.0.0.1`, `::1`);
|
|
1028
|
+
every other host must be `https` (`src/config.js`). If you prefer not to export
|
|
1029
|
+
a variable each session, persist it instead — the env var wins over the file:
|
|
1030
|
+
|
|
1031
|
+
```bash
|
|
1032
|
+
shakers ai-usage --set-endpoint http://127.0.0.1:3000/api/v1/usage/reports
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
Every other URL the CLI needs (`skill-certification`, `login`, the Google
|
|
1036
|
+
config/login pair, `email-verification/request` and `/verify`,
|
|
1037
|
+
`agent-synthesis`, `agent-evaluation`, `graph-inference`, and the
|
|
1038
|
+
`agent-certification/sessions…` / `skill-certification/sessions…` interview
|
|
1039
|
+
routes) is derived as a sibling of whatever `ingestEndpoint` resolves to, so
|
|
1040
|
+
that one variable is enough — `login` first, since `certify` refuses to run
|
|
1041
|
+
without a session (ADR-050):
|
|
1042
|
+
|
|
1043
|
+
```bash
|
|
1044
|
+
shakers login --email you@shakers.com
|
|
1045
|
+
```
|
|
1046
|
+
|
|
1047
|
+
Note the real OTP (for the non-login email-verification path, still used by
|
|
1048
|
+
`ai-usage`'s save-to-Shakers consent) is emailed via HubSpot with a Redis
|
|
1049
|
+
TTL/single-use code — there is no fixed local code any more, so read the one
|
|
1050
|
+
you were sent. There is no fallback hop to exercise any more (ADR-042): an
|
|
1051
|
+
unset or unreachable endpoint fails with the real cause (timeout / connection
|
|
1052
|
+
refused / 5xx), it does not retry anywhere else.
|
|
1053
|
+
|
|
1054
|
+
The CLI's own test suite does not need any of this: it wires an in-process fake
|
|
1055
|
+
(`test-fixtures/ingest-service-fake.js`) into a throwaway server on an ephemeral
|
|
1056
|
+
port. That fake is a **test double, not a runnable server** — it binds no port,
|
|
1057
|
+
has no launcher, is never installed, and only implements what the assertions in
|
|
1058
|
+
`test/` require.
|
|
1059
|
+
|
|
1060
|
+
## How to add a new tool
|
|
1061
|
+
|
|
1062
|
+
Edit `src/detectors.js` and add an entry with its signals:
|
|
1063
|
+
|
|
1064
|
+
```js
|
|
1065
|
+
{
|
|
1066
|
+
id: 'my-tool',
|
|
1067
|
+
name: 'My Tool',
|
|
1068
|
+
vendor: 'Vendor',
|
|
1069
|
+
category: CATEGORIES.AGENTIC_CLI,
|
|
1070
|
+
signals: [
|
|
1071
|
+
{ type: 'projectPath', path: '.mytool' },
|
|
1072
|
+
{ type: 'bin', name: 'mytool' },
|
|
1073
|
+
],
|
|
1074
|
+
}
|
|
1075
|
+
```
|
|
1076
|
+
|
|
1077
|
+
If you want to measure depth, add a probe in `src/scanner.js` inside
|
|
1078
|
+
`probes` that returns **only numbers**.
|
|
1079
|
+
|
|
1080
|
+
## Structure
|
|
1081
|
+
|
|
1082
|
+
```
|
|
1083
|
+
bin/shakers.js Argv command dispatcher + session gate — the single entrypoint (ADR-060/061)
|
|
1084
|
+
bin/ai-usage.js `ai-usage` command logic (run(args,{ask}))
|
|
1085
|
+
bin/certify.js `certify` command logic — skills/agents subcommands + picker (run(args,{ask}))
|
|
1086
|
+
bin/report-html.js `report` command — materialize + open the HTML (run(args,{ask}))
|
|
1087
|
+
bin/share.js `share` command logic — currently disabled (run(args,{ask}))
|
|
1088
|
+
bin/login.js `login`/`logout` command logic (run/runLogout(args,{ask}))
|
|
1089
|
+
bin/superadmin.js `superadmin` non-production test-tool command (run(args,{ask}))
|
|
1090
|
+
|
|
1091
|
+
── ai-usage: detection & classification ──
|
|
1092
|
+
src/detectors.js Catalog of tools and signals
|
|
1093
|
+
src/scanner.js Scan engine -> report object
|
|
1094
|
+
src/scan-exclusions.js Paths/dirs excluded from the scan
|
|
1095
|
+
src/tier-engine.js T0-T7 ladder computation (single source of truth)
|
|
1096
|
+
src/tier-analysis.js "Why this tier" deterministic breakdown
|
|
1097
|
+
src/maturity.js 0-4 band + 0-100 score (derived from the tier)
|
|
1098
|
+
src/mcp-detector.js MCP server name/category detector
|
|
1099
|
+
src/memory-structure-detector.js Context-file import/structure detector
|
|
1100
|
+
src/automations-detector.js Scripts/scheduler automation detector
|
|
1101
|
+
src/browser-tools-detector.js Browser-automation tooling detector
|
|
1102
|
+
src/tech-detector.js Project technologies (frameworks) detector
|
|
1103
|
+
src/tech-extensions.js Technology name map / extensions
|
|
1104
|
+
src/agent-org-chart.js Deterministic agent org chart parser (+ hierarchy)
|
|
1105
|
+
src/agent-synthesis.js Optional LLM agent-card synthesis client
|
|
1106
|
+
src/agent-evaluation.js Optional LLM agent definition-quality client (gemini-2.5-flash, server-side)
|
|
1107
|
+
src/agent-usage.js Local Claude Code history reader (usage signal only, never content)
|
|
1108
|
+
src/roadmap-content.js Curated per-tier roadmap content (es/en)
|
|
1109
|
+
src/roadmap-prompt.js Ready-to-paste implementation prompt
|
|
1110
|
+
src/roadmap-personalization.js Optional LLM roadmap-prose personalization client
|
|
1111
|
+
src/build-next-level.js Secondary: writes deterministic starter files
|
|
1112
|
+
|
|
1113
|
+
── certify: Skill + agent certification ──
|
|
1114
|
+
src/certify-args.js `certify` flag parsing (--skill, --accept-disclaimer, --fast…)
|
|
1115
|
+
src/certify-client.js Resolve/certify HTTP client (discriminated results)
|
|
1116
|
+
src/certify-disclaimer.js Legal disclaimer + explicit acceptance (egress gate, `certify skills`)
|
|
1117
|
+
src/certify-preconditions.js LOGIN precondition for `certify agents` (ADR-050)
|
|
1118
|
+
src/certify-render.js Resolve report renderer
|
|
1119
|
+
src/certify-remediation-prompt.js Copyable remediation prompt per Skill
|
|
1120
|
+
src/certify-agents.js `certify agents` interview flow
|
|
1121
|
+
src/certify-skill-interview.js `certify skills`' mandatory-start skill interview (ADR-049/051)
|
|
1122
|
+
src/interview-engine.js Shared turn-loop/resume/verdict engine (agents + skill interviews)
|
|
1123
|
+
src/agent-certification-client.js HTTP client for both interview kinds' session/turn/verdict routes
|
|
1124
|
+
src/skill-sampler.js Deterministic per-Skill code sampling (+ scrub)
|
|
1125
|
+
src/skill-selection.js --skill selection parsing (by name or position)
|
|
1126
|
+
src/authorship.js Git-authorship filtering/attribution of sampled code (ADR-017)
|
|
1127
|
+
src/interactive-select.js Interactive single-/multi-select picker
|
|
1128
|
+
src/interview-session-store.js Atomic 0600 session-in-flight store (shared by both interview kinds)
|
|
1129
|
+
src/legal-notice.js Shared framing for the four disclosure texts
|
|
1130
|
+
src/render-certification.js Certification report (terminal + HTML sections)
|
|
1131
|
+
src/render-skill-interview.js Skill-interview combined-level verdict renderer
|
|
1132
|
+
|
|
1133
|
+
── login / superadmin ──
|
|
1134
|
+
src/auth-session-store.js Atomic 0600 login-session store (`login`)
|
|
1135
|
+
src/auth-client.js Email/password login HTTP client
|
|
1136
|
+
src/auth-device-client.js Google device-flow HTTP client (RFC 8628: authorize/token/api-token)
|
|
1137
|
+
src/device-login.js Google device-flow orchestration (blocking CLI loop + shared start/poll)
|
|
1138
|
+
src/device-auth-store.js Atomic 0600 pending-device-grant store (bridges the MCP start/poll tools)
|
|
1139
|
+
|
|
1140
|
+
── share: LinkedIn card ──
|
|
1141
|
+
src/share-card.js Builds the self-contained branded SVG/HTML card
|
|
1142
|
+
src/shakers-wordmark.js Inlined "shakers" logotype (auto-generated from SVG)
|
|
1143
|
+
|
|
1144
|
+
── consent, identity, persistence, reporting ──
|
|
1145
|
+
src/consent-flow.js Short, one-time "save to Shakers?" prompt
|
|
1146
|
+
src/consent-skip.js Explicit reasons the consent prompt is/isn't shown
|
|
1147
|
+
src/email-verification.js Email OTP verification client (gates persistence)
|
|
1148
|
+
src/share.js Consent state + derived-payload whitelist + sending
|
|
1149
|
+
src/report-store.js Per-project cumulative report state + HTML (persistence)
|
|
1150
|
+
src/report-theme.js Shared Shakers HTML theme (tokens/base/copy script)
|
|
1151
|
+
src/store.js Legacy latest/history store — UNUSED (kept on disk)
|
|
1152
|
+
src/render-terminal.js Terminal output (why-first, one-line-per-agent; ADR-016)
|
|
1153
|
+
src/render-html.js Self-contained HTML dashboard (full detail, per-agent scores)
|
|
1154
|
+
src/osc-link.js OSC 8 clickable terminal links
|
|
1155
|
+
src/open-file.js Best-effort cross-platform "open in browser" (report/login-browser)
|
|
1156
|
+
|
|
1157
|
+
── graph-inference plumbing (retained; the `map` command was removed) ──
|
|
1158
|
+
src/repo-context.js Content-free structural repo summary (entrypoints, AI call-sites…)
|
|
1159
|
+
src/graph-infer-client.js Optional LLM graph-inference client (gemini-2.5-pro, server-side)
|
|
1160
|
+
src/graph-scan.js Deterministic agent-subgraph + footprint drawer (feeds the sheet)
|
|
1161
|
+
src/graph-generator.js Deterministic graph generation
|
|
1162
|
+
|
|
1163
|
+
── shared plumbing ──
|
|
1164
|
+
src/cli-args.js `ai-usage` flag parsing
|
|
1165
|
+
src/config.js Endpoint configuration from env vars, never hardcoded — one backend (ADR-042)
|
|
1166
|
+
src/config-dir.js Single source for the config dir + legacy `~/.config/ai-footprint` migration (ADR-045)
|
|
1167
|
+
src/env-paths.js Home-directory + `SHAKERS_CLI_*`/`AI_FOOTPRINT_*` env resolution (test-overridable)
|
|
1168
|
+
src/stdin-ask.js Injectable stdin question/answer helper
|
|
1169
|
+
src/terminal-progress.js Status line + spinner for slow calls
|
|
1170
|
+
src/locale.js OS locale detection
|
|
1171
|
+
src/i18n.js Text catalogs (es/en) — report, CLI, certify, login, superadmin
|
|
1172
|
+
|
|
1173
|
+
test-fixtures/ingest-service-fake.js In-process backend FAKE for tests only — not shipped, binds no port
|
|
1174
|
+
install.sh Installer (curl | bash, or local)
|
|
1175
|
+
```
|