codeep 2.1.4 → 2.3.1

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/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  </p>
14
14
 
15
15
  <p align="center">
16
- AI-powered coding assistant built for the terminal. Multiple LLM providers, project-aware context, and a seamless development workflow.
16
+ Autonomous AI coding agent that reads your project, runs commands, and writes &amp; verifies code — deeper than autocomplete. Any model (Claude, Gemini, DeepSeek, GLM, OpenAI, or your own local/custom), in the terminal and your editor.
17
17
  </p>
18
18
 
19
19
  <p align="center">
@@ -242,6 +242,50 @@ Agent learns your coding preferences:
242
242
  - Preferred libraries
243
243
  - Custom rules you define
244
244
 
245
+ ### User Profile (`/me`)
246
+ A durable, human-readable description of **you** that Codeep injects into the agent's context on every run — so it adapts to how you work (reply language, response style, default stack, "always / never" rules). It flows to every surface (terminal, VS Code, Zed) since they share the same files.
247
+
248
+ Two layers:
249
+ - **`~/.codeep/profile.md`** — global: who you are across all projects
250
+ - **`.codeep/profile.md`** — project: your role, goals, and constraints for this repo
251
+
252
+ Commands:
253
+ - `/me` — view your profile + status
254
+ - `/me init [project]` — scaffold a template to fill in
255
+ - `/me on` / `/me off` — toggle injection
256
+ - `/me learn [on|off]` — opt-in auto-learn: Codeep extracts durable preferences from sessions and merges them into `profile.learned.md` (kept separate from your hand-written file). Off by default.
257
+ - `/me learn project` — one-off learn scoped to this repo
258
+ - `/me forget` — clear the auto-learned profile(s)
259
+
260
+ Sync your global profile across machines (and edit it on the web) from the [dashboard](https://codeep.dev/dashboard): `/me sync` (or `codeep account sync`, which now carries the profile too). In VS Code: **Codeep: Edit Profile**, **Codeep: Toggle Profile Auto-Learn**, **Codeep: Sync Profile to Dashboard**.
261
+
262
+ ### Sub-agents (delegation)
263
+ The agent can delegate a self-contained sub-task to a specialist **sub-agent** that runs in its own fresh context window and returns only a summary — keeping the main context small and letting each sub-task run with a tuned persona and scoped tools.
264
+
265
+ Built-ins:
266
+ - **`planner`** — read-only; investigates, then returns a step-by-step implementation plan
267
+ - **`researcher`** — read-only; explores the codebase/web and returns a tight, cited summary
268
+ - **`reviewer`** — read-only; senior review for correctness, security, and design
269
+ - **`tester`** — writes and runs tests, iterates to green
270
+
271
+ Run `/agents` to list them. The agent invokes them itself via the `delegate` tool (you'll see `⤷ <agent>: …` lines). Add your own with a frontmatter `.md` in `.codeep/agents/<name>.md` (project) or `~/.codeep/agents/<name>.md` (global):
272
+
273
+ ```markdown
274
+ ---
275
+ name: migrator
276
+ description: Writes and runs database migrations
277
+ tools: [read_file, write_file, edit_file, execute_command] # allowlist; omit = all
278
+ model: glm-5.1 # optional override
279
+ personality: senior-reviewer # optional preset
280
+ maxIterations: 12 # optional budget
281
+ ---
282
+ You write safe, reversible DB migrations…
283
+ ```
284
+
285
+ `tools` is an allowlist enforced at dispatch (a `researcher` literally can't write files). Sub-agents inherit your profile + project rules, and their changes are covered by `/undo`.
286
+
287
+ **Guaranteed review:** enable **Agent Auto-Review** in `/settings` (`agentAutoReview`) and after any run that changes files, Codeep automatically delegates to the `reviewer` and appends its findings — a review stage that always happens. Off by default.
288
+
245
289
  ### Project Rules
246
290
  Define project-specific instructions that the AI always follows. Create a rules file in your project root:
247
291
 
@@ -644,6 +644,77 @@ Anything else the agent should know — edge cases, gotchas, things to double-ch
644
644
  response: `Active personality: **${p.displayName}** (\`${p.name}\`, ${p.scope})\n\n_${p.description}_\n\nClear with \`/personality off\`.`,
645
645
  };
646
646
  }
647
+ case 'agents': {
648
+ const { formatAgentList } = await import('../utils/agents.js');
649
+ return { handled: true, response: formatAgentList(session.workspaceRoot) };
650
+ }
651
+ case 'me': {
652
+ const { formatProfileView, scaffoldProfile, updateLearnedProfile, clearLearnedProfile, } = await import('../utils/userProfile.js');
653
+ const sub = args[0]?.toLowerCase();
654
+ if (sub === 'on' || sub === 'off') {
655
+ config.set('userProfile', sub === 'on');
656
+ return { handled: true, response: sub === 'on'
657
+ ? "Profile injection on — your profile is added to the agent's context."
658
+ : 'Profile injection off — profile is saved but not used.', configOptionsChanged: true };
659
+ }
660
+ if (sub === 'init') {
661
+ const scope = args[1]?.toLowerCase() === 'project' ? 'project' : 'global';
662
+ if (scope === 'project' && !session.workspaceRoot) {
663
+ return { handled: true, response: 'No project here — use `/me init` for a global profile.' };
664
+ }
665
+ const res = scaffoldProfile(scope, session.workspaceRoot);
666
+ if (!res)
667
+ return { handled: true, response: 'Could not create the profile file.' };
668
+ return { handled: true, response: res.created
669
+ ? `Created ${scope} profile: \`${res.path}\` — edit it and Codeep uses it automatically.`
670
+ : `${scope === 'global' ? 'Global' : 'Project'} profile already exists: \`${res.path}\`.` };
671
+ }
672
+ if (sub === 'learn') {
673
+ const arg = args[1]?.toLowerCase();
674
+ if (arg === 'on' || arg === 'off') {
675
+ config.set('autoLearnProfile', arg === 'on');
676
+ return { handled: true, response: arg === 'on'
677
+ ? 'Auto-learn on — Codeep updates your learned profile (global + project) from sessions.'
678
+ : 'Auto-learn off — Codeep stops updating the learned profile.', configOptionsChanged: true };
679
+ }
680
+ const scope = arg === 'project' ? 'project' : 'global';
681
+ if (scope === 'project' && !session.workspaceRoot) {
682
+ return { handled: true, response: 'No project here — run `/me learn` for your global profile.' };
683
+ }
684
+ if (session.history.filter((m) => m.role !== 'system').length < 2) {
685
+ return { handled: true, response: 'Not enough conversation yet to learn from.' };
686
+ }
687
+ const res = await updateLearnedProfile(session.history, scope, session.workspaceRoot);
688
+ if (!res)
689
+ return { handled: true, response: 'Nothing durable to learn right now (or the model call failed).' };
690
+ const file = scope === 'global' ? '~/.codeep/profile.learned.md' : '.codeep/profile.learned.md';
691
+ return { handled: true, response: res.updated
692
+ ? `Updated your ${scope} learned profile (\`${file}\`):\n\n${res.facts}`
693
+ : `No changes — your ${scope} learned profile already covers this:\n\n${res.facts}` };
694
+ }
695
+ if (sub === 'forget') {
696
+ return { handled: true, response: clearLearnedProfile(session.workspaceRoot)
697
+ ? 'Cleared the auto-learned profile(s).'
698
+ : 'No learned profile to clear.' };
699
+ }
700
+ if (sub === 'sync') {
701
+ const { getSyncToken } = await import('../config/index.js');
702
+ if (!getSyncToken())
703
+ return { handled: true, response: 'Not linked to codeep.dev. Run `codeep account` in a terminal first.' };
704
+ const { pushUserProfile, pullUserProfile } = await import('../utils/codeepCloud.js');
705
+ const pushed = await pushUserProfile();
706
+ const pulled = await pullUserProfile();
707
+ const lines = [];
708
+ if (pushed)
709
+ lines.push('✓ Profile pushed to the dashboard');
710
+ if (pulled === 1)
711
+ lines.push('✓ Profile pulled to this machine');
712
+ if (lines.length === 0)
713
+ lines.push('Nothing to sync yet — run `/me init` and fill in your profile first.');
714
+ return { handled: true, response: lines.join('\n') };
715
+ }
716
+ return { handled: true, response: formatProfileView(session.workspaceRoot) };
717
+ }
647
718
  case 'insights': {
648
719
  const { formatInsights } = await import('../utils/insights.js');
649
720
  let days = 7;
@@ -1375,6 +1446,8 @@ function buildHelp() {
1375
1446
  '| Command | Description |',
1376
1447
  '|---------|-------------|',
1377
1448
  '| `/memory <note>` | Add a project note (or `list` / `remove <n>` / `clear`) |',
1449
+ '| `/me` | Your user profile — reply language, style, stack (`init [project]`, `learn [on\\|off\\|project]`, `forget`, `on`/`off`) |',
1450
+ '| `/agents` | List sub-agents the agent can delegate self-contained tasks to |',
1378
1451
  '| `/profile save <name>` | Save current provider/model/settings (or `load` / `delete` / `list`) |',
1379
1452
  '| `/hooks` | List installed lifecycle hooks (`.codeep/hooks/<event>.sh`) |',
1380
1453
  '',
@@ -58,6 +58,8 @@ const AVAILABLE_COMMANDS = [
58
58
  { name: 'go', description: 'Execute the pending plan from /plan' },
59
59
  // Personalities + insights (2.0.3)
60
60
  { name: 'personality', description: 'List or switch agent tone preset', input: { hint: '[name | off]' } },
61
+ { name: 'me', description: 'Your user profile — adapts the agent to you (reply language, style, stack)', input: { hint: '[init [project] | on | off | learn [on|off|project] | forget | sync]' } },
62
+ { name: 'agents', description: 'List sub-agents the agent can delegate self-contained tasks to' },
61
63
  { name: 'insights', description: 'Activity summary over the last N days (default 7)', input: { hint: '[--days N]' } },
62
64
  // Project intelligence
63
65
  { name: 'scan', description: 'Scan project structure and generate summary' },
@@ -769,7 +771,9 @@ export function startAcpServer() {
769
771
  }
770
772
  else if (configId === 'agentConfirmDeleteFile' ||
771
773
  configId === 'agentConfirmExecuteCommand' ||
772
- configId === 'agentConfirmWriteFile') {
774
+ configId === 'agentConfirmWriteFile' ||
775
+ configId === 'userProfile' ||
776
+ configId === 'autoLearnProfile') {
773
777
  // Accept boolean or "true"/"false" string from Zed/VSCode
774
778
  const bool = value === true || value === 'true';
775
779
  config.set(configId, bool);
@@ -32,6 +32,16 @@ interface ConfigSchema {
32
32
  * discarding them — so long sessions keep early decisions/constraints.
33
33
  * Default true; set false to fall back to plain truncation (no extra call). */
34
34
  autoSummarizeHistory: boolean;
35
+ /** Inject the user profile (`~/.codeep/profile.md` + project
36
+ * `.codeep/profile.md`) into the agent's system prompt so it adapts to the
37
+ * user (reply language, style, stack, preferences). Default true; set false
38
+ * to keep the profile files but stop injecting them. Managed via `/me`. */
39
+ userProfile: boolean;
40
+ /** Auto-learn: at session save, run one LLM pass to extract durable facts /
41
+ * preferences about the user and merge them into `~/.codeep/profile.learned.md`
42
+ * (injected alongside the hand-written profile). OFF by default — opt in via
43
+ * `/me learn on`. Throttled + single-flight so it doesn't spam API calls. */
44
+ autoLearnProfile: boolean;
35
45
  /** Absolute workspace roots whose project-local `.codeep/hooks/*` the user
36
46
  * has approved to run. Untrusted projects' hooks are skipped (a cloned repo
37
47
  * can't execute shell on first tool call). Granted via `/hooks trust`. */
@@ -52,6 +62,10 @@ interface ConfigSchema {
52
62
  agentAutoCommit: boolean;
53
63
  agentAutoCommitBranch: boolean;
54
64
  agentAutoVerify: 'off' | 'build' | 'typecheck' | 'test' | 'all';
65
+ /** After a top-level agent run that changed files, delegate to the `reviewer`
66
+ * sub-agent and append its findings — a guaranteed review stage. Default
67
+ * false (opt-in); one extra nested LLM pass when on. */
68
+ agentAutoReview: boolean;
55
69
  agentMaxFixAttempts: number;
56
70
  agentMaxIterations: number;
57
71
  agentMaxDuration: number;
@@ -152,6 +152,7 @@ function createConfig() {
152
152
  agentAutoCommit: false,
153
153
  agentAutoCommitBranch: false,
154
154
  agentAutoVerify: 'off',
155
+ agentAutoReview: false,
155
156
  // One fix attempt is enough for modern models — if verification fails twice
156
157
  // with the same approach, the agent usually needs human input, not more loops.
157
158
  agentMaxFixAttempts: 1,
@@ -168,6 +169,8 @@ function createConfig() {
168
169
  autoSave: true,
169
170
  autoSessionTitle: true,
170
171
  autoSummarizeHistory: true,
172
+ userProfile: true,
173
+ autoLearnProfile: false,
171
174
  trustedHookProjects: [],
172
175
  currentSessionId: '',
173
176
  temperature: 0.7,
@@ -182,6 +185,19 @@ function createConfig() {
182
185
  syncToken: '',
183
186
  deviceId: '',
184
187
  };
188
+ // Test/CI isolation: when CODEEP_CONFIG_DIR is set, keep config in that
189
+ // directory (one per test worker) so parallel workers don't race on a shared
190
+ // on-disk config file (e.g. clobbering trustedHookProjects). Never set in
191
+ // normal use, so the production resolution below is unchanged.
192
+ const overrideDir = process.env.CODEEP_CONFIG_DIR;
193
+ if (overrideDir) {
194
+ try {
195
+ return new Conf({ projectName: 'codeep', cwd: overrideDir, defaults });
196
+ }
197
+ catch {
198
+ // fall through to standard resolution
199
+ }
200
+ }
185
201
  // First try standard location
186
202
  try {
187
203
  const standardConfig = new Conf({
@@ -686,6 +702,16 @@ export function saveSession(name, history, projectPath) {
686
702
  && history.filter(m => m.role !== 'system').length >= 3) {
687
703
  void maybeGenerateSessionTitle(name, projectPath).catch(() => { });
688
704
  }
705
+ // Fire-and-forget: when the user opted into profile learning, observe the
706
+ // session and merge durable facts into ~/.codeep/profile.learned.md.
707
+ // Throttled + single-flight inside maybeLearnUserProfile, so the 5s
708
+ // autosave cadence doesn't spawn an LLM call every tick. Default off.
709
+ if (config.get('autoLearnProfile') === true
710
+ && history.filter(m => m.role !== 'system').length >= 4) {
711
+ void import('../utils/userProfile.js')
712
+ .then(({ maybeLearnUserProfile }) => maybeLearnUserProfile(name, history, projectPath))
713
+ .catch(() => { });
714
+ }
689
715
  return true;
690
716
  }
691
717
  catch (error) {
@@ -94,6 +94,8 @@ const COMMAND_DESCRIPTIONS = {
94
94
  'plan': 'Generate a numbered plan for a task — review before /go executes it',
95
95
  'go': 'Execute the pending plan from /plan',
96
96
  'personality': 'Switch agent tone: concise / verbose / security / senior-reviewer / etc',
97
+ 'me': 'Your user profile (reply language, style, stack) — adapts the agent to you. /me init, /me learn, /me sync',
98
+ 'agents': 'List sub-agents the agent can delegate self-contained tasks to (researcher / reviewer / tester / custom)',
97
99
  'insights': 'Activity summary over the last N days (default 7): runs, files, tools, projects',
98
100
  'recall': 'Search across ALL saved sessions (cross-session; /search is current-session only)',
99
101
  };
@@ -241,6 +243,10 @@ export class App {
241
243
  'personality', 'insights',
242
244
  // 2.1.0 — cross-session recall.
243
245
  'recall',
246
+ // 2.2.0 — user profile.
247
+ 'me',
248
+ // 2.3.0 — sub-agents / delegation.
249
+ 'agents',
244
250
  'c', 't', 'd', 'r', 'f', 'e', 'o', 'b', 'p',
245
251
  ];
246
252
  constructor(options) {
@@ -252,6 +252,9 @@ export async function handleCommand(command, args, ctx) {
252
252
  commands: 'https://codeep.dev/docs/commands#custom-commands',
253
253
  openrouter: 'https://codeep.dev/docs/providers#openrouter',
254
254
  memory: 'https://codeep.dev/docs/commands#intelligence',
255
+ me: 'https://codeep.dev/docs/agent#user-profile',
256
+ agents: 'https://codeep.dev/docs/agent#sub-agents',
257
+ delegate: 'https://codeep.dev/docs/agent#sub-agents',
255
258
  profile: 'https://codeep.dev/docs/commands#settings',
256
259
  compact: 'https://codeep.dev/docs/commands#session',
257
260
  cost: 'https://codeep.dev/docs/dashboard',
@@ -311,6 +314,110 @@ export async function handleCommand(command, args, ctx) {
311
314
  });
312
315
  break;
313
316
  }
317
+ case 'agents': {
318
+ // List sub-agents the agent can `delegate` to (built-in + .codeep/agents/).
319
+ const { formatAgentList } = await import('../utils/agents.js');
320
+ ctx.app.addMessage({ role: 'system', content: formatAgentList(ctx.projectPath) });
321
+ break;
322
+ }
323
+ case 'me': {
324
+ // User profile (global ~/.codeep/profile.md + project .codeep/profile.md)
325
+ // injected into the agent's context. NOT the provider-profile feature
326
+ // (that's `/profile`). See src/utils/userProfile.ts.
327
+ const { formatProfileView, scaffoldProfile, updateLearnedProfile, clearLearnedProfile } = await import('../utils/userProfile.js');
328
+ const sub = args[0]?.toLowerCase();
329
+ if (sub === 'on' || sub === 'off') {
330
+ config.set('userProfile', sub === 'on');
331
+ ctx.app.notify(sub === 'on'
332
+ ? "Profile injection on — your profile is added to the agent's context."
333
+ : 'Profile injection off — profile is saved but not used.');
334
+ break;
335
+ }
336
+ if (sub === 'learn') {
337
+ const arg = args[1]?.toLowerCase();
338
+ if (arg === 'on' || arg === 'off') {
339
+ config.set('autoLearnProfile', arg === 'on');
340
+ ctx.app.notify(arg === 'on'
341
+ ? 'Auto-learn on — Codeep quietly updates your learned profile (global + project) from sessions.'
342
+ : 'Auto-learn off — Codeep stops updating the learned profile.');
343
+ break;
344
+ }
345
+ // Manual one-off. `/me learn project` targets this repo; otherwise global.
346
+ const scope = arg === 'project' ? 'project' : 'global';
347
+ if (scope === 'project' && !ctx.projectPath) {
348
+ ctx.app.notify('No project detected here — open a project, or run /me learn for your global profile.');
349
+ break;
350
+ }
351
+ const { loadSession } = await import('../config/index.js');
352
+ const history = loadSession(ctx.sessionId, ctx.projectPath) || [];
353
+ if (history.filter((m) => m.role !== 'system').length < 2) {
354
+ ctx.app.notify('Not enough conversation yet to learn from — chat a bit, then run /me learn.');
355
+ break;
356
+ }
357
+ ctx.app.notify(`Learning ${scope} preferences from this session…`);
358
+ const res = await updateLearnedProfile(history, scope, ctx.projectPath);
359
+ if (!res) {
360
+ ctx.app.notify('Nothing durable to learn right now (or the model call failed).');
361
+ break;
362
+ }
363
+ const file = scope === 'global' ? '~/.codeep/profile.learned.md' : '.codeep/profile.learned.md';
364
+ ctx.app.addMessage({
365
+ role: 'system',
366
+ content: res.updated
367
+ ? `Updated your ${scope} learned profile (\`${file}\`):\n\n${res.facts}\n\nClear it anytime with \`/me forget\`.`
368
+ : `No changes — your ${scope} learned profile already covers this:\n\n${res.facts}`,
369
+ });
370
+ break;
371
+ }
372
+ if (sub === 'forget') {
373
+ ctx.app.notify(clearLearnedProfile(ctx.projectPath)
374
+ ? 'Cleared the auto-learned profile(s).'
375
+ : 'No learned profile to clear.');
376
+ break;
377
+ }
378
+ if (sub === 'sync') {
379
+ const { getSyncToken } = await import('../config/index.js');
380
+ if (!getSyncToken()) {
381
+ ctx.app.notify('Not linked to codeep.dev. Run: codeep account');
382
+ break;
383
+ }
384
+ const { pushUserProfile, pullUserProfile } = await import('../utils/codeepCloud.js');
385
+ ctx.app.notify('Syncing your profile with codeep.dev…');
386
+ const pushed = await pushUserProfile();
387
+ const pulled = await pullUserProfile();
388
+ const lines = [];
389
+ if (pushed)
390
+ lines.push('✓ Profile pushed to the dashboard');
391
+ if (pulled === 1)
392
+ lines.push('✓ Profile pulled to this machine');
393
+ if (lines.length === 0)
394
+ lines.push('Nothing to sync yet — run `/me init` and fill in your profile first.');
395
+ ctx.app.addMessage({ role: 'system', content: `## Profile sync\n\n${lines.join('\n')}` });
396
+ break;
397
+ }
398
+ if (sub === 'init') {
399
+ const scope = args[1]?.toLowerCase() === 'project' ? 'project' : 'global';
400
+ if (scope === 'project' && !ctx.projectPath) {
401
+ ctx.app.notify('No project detected here. Use /me init for a global profile, or open a project first.');
402
+ break;
403
+ }
404
+ const res = scaffoldProfile(scope, ctx.projectPath);
405
+ if (!res) {
406
+ ctx.app.notify('Could not create the profile file.');
407
+ break;
408
+ }
409
+ ctx.app.addMessage({
410
+ role: 'system',
411
+ content: res.created
412
+ ? `Created ${scope} profile: \`${res.path}\`\n\nEdit it in your editor — Codeep uses it automatically. View anytime with \`/me\`.`
413
+ : `${scope === 'global' ? 'Global' : 'Project'} profile already exists: \`${res.path}\`\n\nEdit it directly, or view it with \`/me\`.`,
414
+ });
415
+ break;
416
+ }
417
+ // Default: show the profile view.
418
+ ctx.app.addMessage({ role: 'system', content: formatProfileView(ctx.projectPath) });
419
+ break;
420
+ }
314
421
  case 'plan': {
315
422
  // Plan mode: ask the model for a plan, surface it, hold as pending.
316
423
  // The user runs /go to execute or /plan <revised> to revise. See
@@ -1799,6 +1906,15 @@ Describe what this skill does. The agent reads this body verbatim when it invoke
1799
1906
  results.push(`✓ ${pulled} new profile(s) pulled`);
1800
1907
  }
1801
1908
  }
1909
+ // Sync the hand-written user profile (~/.codeep/profile.md). Push sends
1910
+ // the local file; pull is additive (writes only if no local profile).
1911
+ if (subCmd === 'all' || subCmd === 'profile') {
1912
+ const { pushUserProfile, pullUserProfile } = await import('../utils/codeepCloud.js');
1913
+ if (await pushUserProfile())
1914
+ results.push('✓ Your profile (about you) pushed');
1915
+ if ((await pullUserProfile()) === 1)
1916
+ results.push('✓ Your profile pulled to this machine');
1917
+ }
1802
1918
  ctx.app.addMessage({
1803
1919
  role: 'system',
1804
1920
  content: `## Sync\n\n${results.map(r => `- ${r}`).join('\n')}`,
@@ -128,6 +128,11 @@ export const helpCategories = [
128
128
  { key: '/openrouter', description: 'OpenRouter routing prefs (prefer/ignore providers, fallbacks, privacy)' },
129
129
  { key: '/personality', description: 'List or switch agent tone (concise / verbose / security / senior-reviewer / …)' },
130
130
  { key: '/personality <name>', description: 'Activate a personality. /personality off to clear.' },
131
+ { key: '/me', description: 'Your user profile (reply language, style, stack) — adapts the agent to you' },
132
+ { key: '/me init [project]', description: 'Scaffold a profile template (global, or for this project). /me off to disable' },
133
+ { key: '/me learn [on|off]', description: 'Learn durable prefs from this session now; on/off toggles auto-learn. /me forget clears it' },
134
+ { key: '/me sync', description: 'Push your profile to the codeep.dev dashboard (and pull on a fresh machine)' },
135
+ { key: '/agents', description: 'List sub-agents the agent can delegate to (researcher / reviewer / tester / your own)' },
131
136
  { key: '/insights [--days N]', description: 'Activity summary — runs, files, tools, projects over the last N days (default 7)' },
132
137
  ],
133
138
  },
@@ -179,6 +179,16 @@ export const SETTINGS = [
179
179
  { value: 'all', label: 'Build + Typecheck + Test' },
180
180
  ],
181
181
  },
182
+ {
183
+ key: 'agentAutoReview',
184
+ label: 'Agent Auto-Review',
185
+ getValue: () => config.get('agentAutoReview'),
186
+ type: 'select',
187
+ options: [
188
+ { value: true, label: 'On (reviewer pass after changes)' },
189
+ { value: false, label: 'Off' },
190
+ ],
191
+ },
182
192
  {
183
193
  key: 'agentAutoCommit',
184
194
  label: 'Agent Auto-Commit',
@@ -386,8 +386,8 @@ Codeep - AI-powered coding assistant TUI
386
386
  Usage:
387
387
  codeep Start interactive chat
388
388
  codeep account Link CLI to your codeep.dev dashboard
389
- codeep account sync Pull keys + personalities + commands from codeep.dev
390
- codeep account push Push local keys + personalities + commands to codeep.dev
389
+ codeep account sync Pull keys + personalities + commands + profile from codeep.dev
390
+ codeep account push Push local keys + personalities + commands + profile to codeep.dev
391
391
  codeep acp Start ACP server (for Zed editor integration)
392
392
  codeep --version Show version
393
393
  codeep --help Show this help
@@ -427,9 +427,9 @@ Commands (in chat):
427
427
  }
428
428
  console.log(` synced ${count} key${count !== 1 ? 's' : ''}.`);
429
429
  }
430
- // Also pull portable personal config — personalities + custom
431
- // commands. Additive merge (never clobbers local files).
432
- const { pullPersonalities, pullCommands } = await import('../utils/codeepCloud.js');
430
+ // Also pull portable personal config — personalities + custom commands +
431
+ // the user profile. Additive merge (never clobbers local files).
432
+ const { pullPersonalities, pullCommands, pullUserProfile } = await import('../utils/codeepCloud.js');
433
433
  const pCount = await pullPersonalities();
434
434
  if (typeof pCount === 'number' && pCount > 0) {
435
435
  console.log(` Pulled ${pCount} personalit${pCount === 1 ? 'y' : 'ies'}.`);
@@ -438,6 +438,10 @@ Commands (in chat):
438
438
  if (typeof cCount === 'number' && cCount > 0) {
439
439
  console.log(` Pulled ${cCount} custom command${cCount === 1 ? '' : 's'}.`);
440
440
  }
441
+ const profPulled = await pullUserProfile();
442
+ if (profPulled === 1) {
443
+ console.log(' Pulled your profile (about you).');
444
+ }
441
445
  console.log('');
442
446
  process.exit(0);
443
447
  }
@@ -465,8 +469,8 @@ Commands (in chat):
465
469
  process.stdout.write(` Pushing ${count} key${count !== 1 ? 's' : ''} to codeep.dev...`);
466
470
  const ok = await pushKeys(keys);
467
471
  console.log(ok ? ' done.' : ' failed.');
468
- // Also push portable personal config.
469
- const { pushPersonalities, pushCommands } = await import('../utils/codeepCloud.js');
472
+ // Also push portable personal config — personalities + commands + profile.
473
+ const { pushPersonalities, pushCommands, pushUserProfile } = await import('../utils/codeepCloud.js');
470
474
  const pCount = await pushPersonalities();
471
475
  if (typeof pCount === 'number' && pCount > 0) {
472
476
  console.log(` Pushed ${pCount} personalit${pCount === 1 ? 'y' : 'ies'}.`);
@@ -475,6 +479,9 @@ Commands (in chat):
475
479
  if (typeof cCount === 'number' && cCount > 0) {
476
480
  console.log(` Pushed ${cCount} custom command${cCount === 1 ? '' : 's'}.`);
477
481
  }
482
+ if (await pushUserProfile()) {
483
+ console.log(' Pushed your profile (about you).');
484
+ }
478
485
  console.log('');
479
486
  process.exit(ok ? 0 : 1);
480
487
  }
@@ -56,6 +56,20 @@ export interface AgentOptions {
56
56
  role: 'user' | 'assistant';
57
57
  content: string;
58
58
  }>;
59
+ /** Delegated sub-agent run. Skips the undo/history session + progress log so
60
+ * it doesn't clobber the parent's (history.ts uses a module-level
61
+ * `currentSession` singleton — a nested startSession would reset it). The
62
+ * sub-agent's tool actions still record into the parent's session, so undo
63
+ * spans delegation. */
64
+ nested?: boolean;
65
+ /** Delegation depth. 0 = top-level orchestrator (gets the `delegate` tool);
66
+ * sub-agents run at depth 1 and cannot delegate further (v1). */
67
+ depth?: number;
68
+ /** Tool allowlist for a scoped sub-agent. Undefined = all tools. Enforced at
69
+ * dispatch — a disallowed tool call returns an error result. */
70
+ allowedTools?: string[];
71
+ /** Role system-prompt addendum injected for a delegated sub-agent. */
72
+ roleAddendum?: string;
59
73
  }
60
74
  export interface AgentResult {
61
75
  success: boolean;