@pellux/goodvibes-agent 1.0.33 → 1.0.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +71 -59
  3. package/dist/package/main.js +565 -420
  4. package/docs/README.md +25 -21
  5. package/docs/channels-remote-and-api.md +2 -2
  6. package/docs/connected-host.md +3 -3
  7. package/docs/getting-started.md +87 -86
  8. package/docs/providers-and-routing.md +3 -3
  9. package/docs/release-and-publishing.md +3 -3
  10. package/docs/tools-and-commands.md +149 -139
  11. package/docs/voice-and-live-tts.md +1 -1
  12. package/package.json +1 -1
  13. package/release/live-verification/live-verification.json +2 -2
  14. package/release/live-verification/live-verification.md +2 -2
  15. package/release/release-notes.md +6 -15
  16. package/release/release-readiness.json +4 -4
  17. package/src/agent/harness-control.ts +42 -3
  18. package/src/runtime/bootstrap.ts +10 -18
  19. package/src/tools/agent-analysis-registry-policy.ts +2 -9
  20. package/src/tools/agent-channel-send-tool.ts +1 -5
  21. package/src/tools/agent-context-policy.ts +1 -5
  22. package/src/tools/agent-find-policy.ts +1 -4
  23. package/src/tools/agent-harness-channel-metadata.ts +23 -23
  24. package/src/tools/agent-harness-cli-metadata.ts +4 -1
  25. package/src/tools/agent-harness-command-catalog.ts +10 -3
  26. package/src/tools/agent-harness-connected-host-status.ts +8 -2
  27. package/src/tools/agent-harness-delegation-posture.ts +5 -5
  28. package/src/tools/agent-harness-mcp-metadata.ts +30 -28
  29. package/src/tools/agent-harness-media-posture.ts +9 -9
  30. package/src/tools/agent-harness-metadata.ts +25 -7
  31. package/src/tools/agent-harness-model-routing.ts +14 -14
  32. package/src/tools/agent-harness-model-tool-catalog.ts +7 -2
  33. package/src/tools/agent-harness-notification-metadata.ts +17 -17
  34. package/src/tools/agent-harness-pairing-posture.ts +7 -7
  35. package/src/tools/agent-harness-panel-metadata.ts +26 -12
  36. package/src/tools/agent-harness-provider-account-metadata.ts +33 -31
  37. package/src/tools/agent-harness-security-posture.ts +9 -7
  38. package/src/tools/agent-harness-service-posture.ts +22 -16
  39. package/src/tools/agent-harness-session-metadata.ts +9 -7
  40. package/src/tools/agent-harness-setup-posture.ts +6 -6
  41. package/src/tools/agent-harness-tool-schema.ts +1 -0
  42. package/src/tools/agent-harness-tool.ts +79 -36
  43. package/src/tools/agent-harness-ui-surface-metadata.ts +19 -11
  44. package/src/tools/agent-harness-workspace-actions.ts +29 -1
  45. package/src/tools/agent-knowledge-ingest-tool.ts +1 -5
  46. package/src/tools/agent-knowledge-tool.ts +1 -5
  47. package/src/tools/agent-local-registry-tool.ts +1 -4
  48. package/src/tools/agent-media-generate-tool.ts +1 -5
  49. package/src/tools/agent-notify-tool.ts +1 -5
  50. package/src/tools/agent-operator-action-tool.ts +1 -5
  51. package/src/tools/agent-operator-briefing-tool.ts +1 -5
  52. package/src/tools/agent-read-policy.ts +1 -4
  53. package/src/tools/agent-reminder-schedule-tool.ts +1 -5
  54. package/src/tools/agent-tool-policy-guard.ts +7 -34
  55. package/src/tools/agent-web-search-policy.ts +1 -4
  56. package/src/tools/agent-work-plan-tool.ts +1 -5
  57. package/src/version.ts +1 -1
@@ -77,6 +77,18 @@ export interface HarnessSettingDescriptor {
77
77
  readonly lookup?: HarnessSettingLookup;
78
78
  }
79
79
 
80
+ export interface HarnessSettingSummary {
81
+ readonly key: string;
82
+ readonly category: string;
83
+ readonly type: ConfigSetting['type'];
84
+ readonly value: unknown;
85
+ readonly configured: boolean;
86
+ readonly writable: boolean;
87
+ readonly visibleInWorkspace: boolean;
88
+ readonly summary: string;
89
+ readonly enumValues?: readonly string[];
90
+ }
91
+
80
92
  export interface HarnessSettingMutationResult {
81
93
  readonly key: string;
82
94
  readonly action: 'set' | 'reset';
@@ -91,6 +103,11 @@ function valuesEqual(left: unknown, right: unknown): boolean {
91
103
  return JSON.stringify(left) === JSON.stringify(right);
92
104
  }
93
105
 
106
+ function previewText(value: string, maxLength = 120): string {
107
+ const normalized = value.replace(/\s+/g, ' ').trim();
108
+ return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 1).trimEnd()}...`;
109
+ }
110
+
94
111
  function clampLimit(value: unknown, fallback = DEFAULT_SETTING_LIMIT): number {
95
112
  if (typeof value !== 'number' || !Number.isFinite(value)) return fallback;
96
113
  return Math.max(1, Math.min(500, Math.trunc(value)));
@@ -164,10 +181,30 @@ export function describeHarnessSetting(
164
181
  };
165
182
  }
166
183
 
184
+ export function describeHarnessSettingSummary(
185
+ configManager: Pick<ConfigManager, 'get'>,
186
+ setting: ConfigSetting,
187
+ ): HarnessSettingSummary {
188
+ const value = configManager.get(setting.key as ConfigKey);
189
+ const hostOwned = isExternalHostOwnedSettingKey(setting.key);
190
+ return {
191
+ key: setting.key,
192
+ category: setting.key.split('.')[0] ?? '',
193
+ type: setting.type,
194
+ value: redactHarnessSettingValue(setting.key, value),
195
+ configured: !valuesEqual(value, setting.default),
196
+ writable: !hostOwned,
197
+ visibleInWorkspace: !isAgentHiddenSettingKey(setting.key),
198
+ summary: previewText(setting.description),
199
+ ...(setting.enumValues ? { enumValues: setting.enumValues } : {}),
200
+ };
201
+ }
202
+
167
203
  export function listHarnessSettings(
168
204
  configManager: Pick<ConfigManager, 'get' | 'getSchema'>,
169
205
  filters: HarnessSettingFilters = {},
170
- ): readonly HarnessSettingDescriptor[] {
206
+ options: { readonly includeParameters?: boolean } = {},
207
+ ): readonly (HarnessSettingDescriptor | HarnessSettingSummary)[] {
171
208
  const key = filters.key?.trim();
172
209
  const category = filters.category?.trim();
173
210
  const prefix = filters.prefix?.trim();
@@ -185,7 +222,9 @@ export function listHarnessSettings(
185
222
  }
186
223
  return true;
187
224
  })
188
- .map((setting) => describeHarnessSetting(configManager, setting))
225
+ .map((setting) => options.includeParameters
226
+ ? describeHarnessSetting(configManager, setting)
227
+ : describeHarnessSettingSummary(configManager, setting))
189
228
  .slice(0, limit);
190
229
  }
191
230
 
@@ -358,7 +397,7 @@ export async function resetHarnessSetting(
358
397
  };
359
398
  }
360
399
 
361
- export function formatHarnessSettingList(settings: readonly HarnessSettingDescriptor[]): string {
400
+ export function formatHarnessSettingList(settings: readonly (HarnessSettingDescriptor | HarnessSettingSummary)[]): string {
362
401
  if (settings.length === 0) return 'No settings matched.';
363
402
  return [
364
403
  `Settings (${settings.length})`,
@@ -46,24 +46,16 @@ import { registerAgentHarnessTool } from '../tools/agent-harness-tool.ts';
46
46
 
47
47
  const GOODVIBES_AGENT_OPERATOR_POLICY = [
48
48
  '## GoodVibes Agent Operator Policy',
49
- '- Default to serial, proactive assistant work in the main conversation. Answer, inspect, summarize, remember useful non-secret facts, configure Agent-local state, use read-only connected-host/operator routes, and take safe non-destructive actions without creating separate Agent jobs or GoodVibes TUI delegations.',
50
- '- GoodVibes Agent connects to a GoodVibes host owned outside this package. Do not start, stop, restart, install, expose, or mutate connected-host network/listener posture from Agent.',
51
- '- Use the `agent_operator_briefing` tool for read-only main-conversation summaries of connected work plan, approvals, automation, schedules, and scheduler capacity. This tool must not call mutation routes, connected-host lifecycle routes, default knowledge, non-Agent knowledge spaces, separate Agent job creation, or GoodVibes TUI delegation.',
52
- '- When the user explicitly asks Agent to approve, deny, or cancel a specific approval, run/pause/resume a specific automation job, cancel/retry a specific automation run, or run a specific schedule, use the `agent_operator_action` tool with confirm:true and the original user request. It can call only its allowlisted public operator routes and must not create, edit, delete, or discover automation definitions.',
53
- '- Use the `agent_work_plan` tool to keep the visible Agent-local work plan current while working in the main conversation. Create, inspect, and update local work items proactively when useful. Removing items or clearing completed items requires an explicit user request and confirm:true.',
54
- '- Use the `agent_harness` tool to inspect and operate the harness surface itself: Agent workspace action catalog, slash command catalog, model tool catalog, release evidence bundle, release readiness inventory, connected-host posture, and Agent settings. Use it to change Agent settings, invoke workspace action mirrors, or invoke slash-command mirrors only when the user explicitly asks; preserve confirm:true and explicitUserRequest for mutations, keep secret-backed settings in the secret manager, and keep connected-host lifecycle/posture externally owned.',
55
- '- Use the `agent_knowledge` tool for Agent Knowledge status, ask, search, source/node/issue lists, item lookup, map summary, connector list/detail, and connector doctor from the main conversation. It must use only /api/goodvibes-agent/knowledge/* and must fail closed instead of falling back to default knowledge or non-Agent knowledge spaces.',
56
- '- When the user explicitly asks Agent to add, import, remember, or ingest a URL, URL-list file, local file, bookmarks file, browser history, or connector input into Agent Knowledge, use the `agent_knowledge_ingest` tool with confirm:true and the original user request. It must write only to /api/goodvibes-agent/knowledge/* ingest routes and never to default knowledge or non-Agent knowledge spaces.',
57
- '- Use the `agent_local_registry` tool when a scratchpad note, durable memory, reusable persona, skill, skill bundle, or routine would improve later work. Keep those records Agent-local, non-secret, source/provenance tagged, and reviewable. Notes are for temporary/source-triage context; promote them explicitly into memory, skills, personas, routines, or Agent Knowledge only when that is the correct durable home. Review memory with a confidence score when it should shape later turns. Starting a routine means applying its steps in this same serial conversation, not creating a background job.',
58
- '- When the user explicitly asks Agent to generate an image, video, or other media artifact, use the `agent_media_generate` tool with confirm:true and the original user request. Generated media is stored as artifacts; do not print base64, call default knowledge, use non-Agent knowledge spaces, send channels, create separate Agent jobs, or request GoodVibes TUI delegation for media generation.',
59
- '- When the user explicitly asks Agent to send an alert, message, or notification to configured notification targets, use the `agent_notify` tool with confirm:true and the original user request. Do not infer external notifications from vague suggestions, and never create channel routes or account authorizations from the main conversation.',
60
- '- When the user explicitly asks Agent to send one message to a specific configured channel, route, webhook, or link target, use the `agent_channel_send` tool with confirm:true and the original user request. It can deliver one message through configured delivery strategies, but must not create routes, authorize accounts, manage connected-host hosting, use default knowledge, use non-Agent knowledge spaces, create separate Agent jobs, or request GoodVibes TUI delegation.',
61
- '- When the user explicitly asks for a reminder or asks Agent to schedule a reminder, use the `agent_reminder_schedule` tool with confirm:true and the original user request. That creates one connected schedules.create reminder on the external GoodVibes host. Do not infer reminders from vague suggestions or routine startup, and never create local scheduler jobs.',
62
- '- GoodVibes TUI delegation is never the default Agent reasoning path. Do not delegate planning, research, operations, knowledge, memory, configuration, approvals, automation observability, or ordinary assistant work.',
63
- '- GoodVibes Agent is not the coding TUI. Do not use the `agent` tool to create coding-role Agent jobs or batch job roots from Agent.',
64
- '- When the user explicitly asks to build, implement, fix, patch, or review code, preserve the full original user ask and delegate one build request to GoodVibes TUI through the public shared-session/build-delegation contract. Include clear executionIntent and request delegated review only for explicit build/fix/review work or when the user explicitly asks for delegated Agent review.',
65
- '- Do not narrow explicit build/fix/review requests into design-only, read-only, or no-write work unless the user explicitly requested that limitation. TUI owns file edits, git/worktree work, execution isolation UX, and delegated review coordination.',
66
- '- If a stable public delegation route is unavailable, say that the task needs GoodVibes TUI delegation and report the missing route instead of pretending to implement it locally or creating sibling Agent jobs.',
49
+ '- Work serially in the main conversation by default: answer, inspect, summarize, remember useful non-secret facts, configure Agent-local state, and use safe read-only connected-host/operator routes.',
50
+ '- Connected-host lifecycle is external. Do not start, stop, restart, install, expose, or mutate host listeners/network posture from Agent.',
51
+ '- Read tools: `agent_operator_briefing` for connected work/approvals/automation/schedules, `agent_knowledge` for isolated Agent Knowledge, `agent_harness` for harness catalogs/settings/status.',
52
+ '- State tools: `agent_work_plan` for visible local work items; `agent_local_registry` for Agent-local notes, memory, personas, skills, bundles, and routines. Keep records non-secret, sourced, and reviewable.',
53
+ '- Confirmed tools: use `agent_operator_action`, `agent_knowledge_ingest`, `agent_media_generate`, `agent_notify`, `agent_channel_send`, and `agent_reminder_schedule` only for explicit user requests with confirm:true and explicitUserRequest.',
54
+ '- Agent Knowledge must use only `/api/goodvibes-agent/knowledge/*` and fail closed. Do not use default knowledge or non-Agent knowledge spaces.',
55
+ '- External delivery, media generation, reminders, settings writes, slash-command mirrors, workspace action mirrors, and destructive local changes require explicit user intent and the owning tool/command confirmation.',
56
+ '- Routines run in this serial conversation unless explicitly promoted to a connected schedule. Do not create hidden Agent jobs or local scheduler jobs.',
57
+ '- Do not delegate planning, research, operations, knowledge, memory, configuration, approvals, observability, or ordinary assistant work.',
58
+ '- For explicit build, implement, fix, patch, or review requests, preserve the full original ask and use the public shared-session/build-delegation route. If that route is unavailable, report the missing route instead of pretending to perform the work locally.',
67
59
  ].join('\n');
68
60
 
69
61
  function joinPromptParts(...parts: Array<string | null | undefined>): string {
@@ -82,11 +82,7 @@ export function validateRegistryToolInvocationForAgentPolicy(args: RegistryToolA
82
82
  }
83
83
 
84
84
  function narrowAnalyzeToolDefinitionForAgentPolicy(tool: Tool): void {
85
- tool.definition.description = [
86
- 'Run local, static project analysis for GoodVibes Agent.',
87
- 'npm registry upgrade checks and hidden secondary LLM diff analysis are disabled in the main conversation.',
88
- 'Delegate package-upgrade and review workflows to GoodVibes TUI when they become build/fix/review work.',
89
- ].join(' ');
85
+ tool.definition.description = 'Run local, static project analysis for GoodVibes Agent.';
90
86
  tool.definition.sideEffects = ['read_fs'];
91
87
 
92
88
  const properties = tool.definition.parameters.properties;
@@ -101,10 +97,7 @@ function narrowAnalyzeToolDefinitionForAgentPolicy(tool: Tool): void {
101
97
  }
102
98
 
103
99
  function narrowRegistryToolDefinitionForAgentPolicy(tool: Tool): void {
104
- tool.definition.description = [
105
- 'Discover and preview GoodVibes Agent skills, agents, and tools.',
106
- 'Full content materialization and arbitrary .goodvibes file reads are disabled in the main conversation.',
107
- ].join(' ');
100
+ tool.definition.description = 'Discover and preview GoodVibes Agent registry entries.';
108
101
  tool.definition.sideEffects = ['read_fs'];
109
102
 
110
103
  const properties = tool.definition.parameters.properties;
@@ -41,11 +41,7 @@ export function createAgentChannelSendTool(
41
41
  return {
42
42
  definition: {
43
43
  name: 'agent_channel_send',
44
- description: [
45
- 'Send one confirmed message through a configured Agent target.',
46
- 'Use only for explicit send/message/alert requests.',
47
- 'Provide exactly one target.',
48
- ].join(' '),
44
+ description: 'Send one confirmed message through one configured Agent target.',
49
45
  parameters: {
50
46
  type: 'object',
51
47
  properties: {
@@ -7,11 +7,7 @@ const CONTEXT_TOOL_DENIAL = [
7
7
  ].join(' ');
8
8
 
9
9
  export function wrapBlockedContextToolForAgentPolicy(tool: Tool): void {
10
- tool.definition.description = [
11
- 'Blocked in GoodVibes Agent main conversation: non-Agent runtime context.',
12
- 'Use explicit Agent CLI/slash status, compat, setup, and Agent Knowledge commands for product-scoped context.',
13
- 'Default knowledge, non-Agent knowledge segments, and non-Agent runtime assumptions are not Agent fallbacks.',
14
- ].join(' ');
10
+ tool.definition.description = 'Blocked in GoodVibes Agent: non-Agent runtime context.';
15
11
  tool.definition.sideEffects = [];
16
12
  tool.definition.parameters = {
17
13
  type: 'object',
@@ -82,10 +82,7 @@ export function normalizeFindToolInvocationForAgentPolicy(args: FindToolArgs): F
82
82
  }
83
83
 
84
84
  function narrowFindToolDefinitionForAgentPolicy(tool: Tool): void {
85
- tool.definition.description = [
86
- 'Search the project for GoodVibes Agent using serial, gitignore-respecting read-only queries.',
87
- 'Hidden-file scans, symlink traversal, gitignore bypass, broad previews, full symbol dumps, and parallel search are disabled in the main conversation.',
88
- ].join(' ');
85
+ tool.definition.description = 'Search project files with serial, gitignore-respecting read-only queries.';
89
86
  tool.definition.sideEffects = ['read_fs'];
90
87
  tool.definition.concurrency = 'serial';
91
88
 
@@ -83,31 +83,31 @@ function describeChannel(
83
83
  defaultTargetKeys: channel.defaultTargetKeys,
84
84
  configuredDefaultTargetKeys: channel.configuredDefaultTargetKeys,
85
85
  ...(options.lookup ? { lookup: options.lookup } : {}),
86
- policy: {
87
- effect: 'read-only',
88
- values: 'Config key names and target key names are shown; secret values and stored target values are never returned.',
89
- delivery: 'Use agent_channel_send only for one explicit, confirmed delivery target requested by the user.',
90
- setup: 'Use connected-host setup/account/policy routes only as read-only diagnostics unless another confirmed first-class tool owns the mutation.',
91
- },
92
- modelAccess: {
93
- sendTool: 'agent_channel_send',
94
- notificationTool: 'agent_notify',
95
- reminderTool: 'agent_reminder_schedule',
96
- slashCommandDetail: `/channels show ${channel.id}`,
97
- readOnlyConnectedRoutes: [
98
- '/channels accounts',
99
- '/channels policies',
100
- '/channels status',
101
- `/channels doctor ${channel.id}`,
102
- `/channels setup ${channel.id}`,
103
- ],
104
- settingsFilter: `agent_harness mode:"settings" prefix:"surfaces.${channel.id}" includeHidden:true`,
105
- connectedHostBoundary: 'agent_harness mode:"connected_host_capability" query:"delivery"',
106
- ...(options.includeParameters ? {
86
+ ...(options.includeParameters ? {
87
+ policy: {
88
+ effect: 'read-only',
89
+ values: 'Config key names and target key names are shown; secret values and stored target values are never returned.',
90
+ delivery: 'Use agent_channel_send only for one explicit, confirmed delivery target requested by the user.',
91
+ setup: 'Use connected-host setup/account/policy routes only as read-only diagnostics unless another confirmed first-class tool owns the mutation.',
92
+ },
93
+ modelAccess: {
94
+ sendTool: 'agent_channel_send',
95
+ notificationTool: 'agent_notify',
96
+ reminderTool: 'agent_reminder_schedule',
97
+ slashCommandDetail: `/channels show ${channel.id}`,
98
+ readOnlyConnectedRoutes: [
99
+ '/channels accounts',
100
+ '/channels policies',
101
+ '/channels status',
102
+ `/channels doctor ${channel.id}`,
103
+ `/channels setup ${channel.id}`,
104
+ ],
105
+ settingsFilter: `agent_harness mode:"settings" prefix:"surfaces.${channel.id}" includeHidden:true`,
106
+ connectedHostBoundary: 'agent_harness mode:"connected_host_capability" query:"delivery"',
107
107
  deliveryTargetShape: 'surface[:route[:label]]',
108
108
  exampleTarget: `${channel.id}:route:Label`,
109
- } : {}),
110
- },
109
+ },
110
+ } : {}),
111
111
  };
112
112
  }
113
113
 
@@ -14,6 +14,7 @@ export interface AgentHarnessCliArgs {
14
14
  readonly cliCommand?: unknown;
15
15
  readonly commandName?: unknown;
16
16
  readonly target?: unknown;
17
+ readonly includeParameters?: unknown;
17
18
  readonly limit?: unknown;
18
19
  }
19
20
 
@@ -106,12 +107,14 @@ export function blockedHarnessCliCommandTokens(): readonly string[] {
106
107
  export function listHarnessCliCommands(args: AgentHarnessCliArgs): readonly Record<string, unknown>[] {
107
108
  const query = readString(args.query);
108
109
  const limit = readLimit(args.limit, 200);
110
+ const includeParameters = args.includeParameters === true;
109
111
  return listGoodVibesCliCommands()
110
112
  .filter((command) => command !== 'unknown')
111
113
  .map((command) => describeCliCommand(command))
112
114
  .filter((command) => cliCommandMatches(command, query))
113
115
  .sort((a, b) => String(a.name).localeCompare(String(b.name)))
114
- .slice(0, limit);
116
+ .slice(0, limit)
117
+ .map((command) => includeParameters ? command : cliCommandCandidate(command));
115
118
  }
116
119
 
117
120
  function cliInputFromArgs(args: AgentHarnessCliArgs): { readonly source: CliCommandLookup['source']; readonly input: string } | null {
@@ -8,6 +8,7 @@ export interface AgentHarnessCommandCatalogArgs {
8
8
  readonly commandName?: unknown;
9
9
  readonly args?: unknown;
10
10
  readonly target?: unknown;
11
+ readonly includeParameters?: unknown;
11
12
  readonly limit?: unknown;
12
13
  }
13
14
 
@@ -38,6 +39,11 @@ function readStringArray(value: unknown): readonly string[] {
38
39
  return value.map((entry) => typeof entry === 'string' ? entry : String(entry));
39
40
  }
40
41
 
42
+ function previewText(value: string, maxLength = 120): string {
43
+ const normalized = value.replace(/\s+/g, ' ').trim();
44
+ return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 1).trimEnd()}...`;
45
+ }
46
+
41
47
  function commandMatches(command: SlashCommand, query: string): boolean {
42
48
  if (!query) return true;
43
49
  const haystack = [
@@ -76,8 +82,8 @@ function describeCommandCandidate(command: SlashCommand): Record<string, unknown
76
82
  name: command.name,
77
83
  slash: `/${command.name}`,
78
84
  aliases: command.aliases ?? [],
79
- description: command.description,
80
- usage: command.usage ?? '',
85
+ summary: previewText(command.description),
86
+ ...(command.argsHint ? { argsHint: command.argsHint } : {}),
81
87
  };
82
88
  }
83
89
 
@@ -165,11 +171,12 @@ export function resolveHarnessCommandDetail(commandRegistry: CommandRegistry, ar
165
171
  export function listHarnessCommands(commandRegistry: CommandRegistry, args: AgentHarnessCommandCatalogArgs): readonly Record<string, unknown>[] {
166
172
  const query = readString(args.query);
167
173
  const limit = readLimit(args.limit, 200);
174
+ const includeParameters = args.includeParameters === true;
168
175
  return commandRegistry.list()
169
176
  .filter((command) => commandMatches(command, query))
170
177
  .sort((a, b) => a.name.localeCompare(b.name))
171
178
  .slice(0, limit)
172
- .map((command) => describeCommand(command));
179
+ .map((command) => includeParameters ? describeCommand(command) : describeCommandCandidate(command));
173
180
  }
174
181
 
175
182
  export function describeHarnessCommand(commandRegistry: CommandRegistry, args: AgentHarnessCommandCatalogArgs): Record<string, unknown> | null {
@@ -73,6 +73,7 @@ function connectedHostFindings(
73
73
  export async function connectedHostStatusSummary(
74
74
  context: CommandContext,
75
75
  toolRegistry: ToolRegistry,
76
+ options: { readonly includeParameters?: boolean } = {},
76
77
  ): Promise<Record<string, unknown>> {
77
78
  const homeDirectory = resolveHomeDirectory(context);
78
79
  const workingDirectory = resolveWorkingDirectory(context);
@@ -134,13 +135,18 @@ export async function connectedHostStatusSummary(
134
135
  },
135
136
  ],
136
137
  findings: connectedHostFindings(runtime, tokenUsable),
137
- modelAccess: {
138
+ capabilitySummary: {
139
+ routeFamilies: connectedHostRouteFamilies().length,
140
+ availableCapabilities: connectedHostCapabilityMap(toolRegistry).filter((capability) => capability.available === true).length,
141
+ blockedCapabilities: blockedConnectedHostCapabilities().length,
142
+ },
143
+ ...(options.includeParameters ? { modelAccess: {
138
144
  diagnostics: 'Use mode:"connected_host_status" for live read-only host readiness, mode:"service_posture" for endpoint posture, mode:"service_endpoint" for one endpoint, and mode:"connected_host" for capability and boundary inventory.',
139
145
  cliMirrors: ['goodvibes-agent status --json', 'goodvibes-agent doctor', 'goodvibes-agent compat'],
140
146
  tuiMirrors: ['Agent Workspace -> Home -> Host compatibility', 'Agent Workspace -> Home -> Doctor diagnostics', 'Agent Workspace -> Home -> Review health'],
141
147
  },
142
148
  routeFamilies: connectedHostRouteFamilies(),
143
149
  capabilities: connectedHostCapabilityMap(toolRegistry),
144
- blockedCapabilities: blockedConnectedHostCapabilities(),
150
+ blockedCapabilities: blockedConnectedHostCapabilities() } : {}),
145
151
  };
146
152
  }
@@ -136,12 +136,12 @@ function describeRoute(
136
136
  operatorClientAttached: Boolean(context.clients?.operator),
137
137
  },
138
138
  ...(options.lookup ? { lookup: options.lookup } : {}),
139
- policy: {
140
- effect: route.effect,
141
- values: 'Delegation posture returns policy, route, confirmation, and runtime availability metadata only; it does not submit delegated work.',
142
- mutation: 'Delegated work submission stays a visible confirmed workspace or slash-command flow and must preserve the full original user ask.',
143
- },
144
139
  ...(options.includeParameters ? {
140
+ policy: {
141
+ effect: route.effect,
142
+ values: 'Delegation posture returns policy, route, confirmation, and runtime availability metadata only; it does not submit delegated work.',
143
+ mutation: 'Delegated work submission stays a visible confirmed workspace or slash-command flow and must preserve the full original user ask.',
144
+ },
145
145
  modelAccess: {
146
146
  inspectDelegation: 'agent_harness mode:"delegation_posture"',
147
147
  inspectRoute: 'agent_harness mode:"delegation_route"',
@@ -116,34 +116,36 @@ function describeServer(
116
116
  })),
117
117
  toolCount: tools.length,
118
118
  } : { toolCount: tools.length }),
119
- policy: {
120
- effect: 'read-only',
121
- values: 'Server posture returns trust, role, connection, quarantine, and tool metadata; env values and secret config values are never returned.',
122
- mutation: 'MCP add/remove/reload/trust/role/quarantine operations stay explicit confirmation-gated workspace or slash-command flows.',
123
- allowAll: 'allow-all trust decisions remain routed through Settings -> MCP, not direct command escalation.',
124
- },
125
- modelAccess: {
126
- reviewCommand: '/mcp review',
127
- serversCommand: '/mcp servers',
128
- toolsCommand: `/mcp tools ${server.name}`,
129
- repairCommand: `/mcp repair ${server.name}`,
130
- authReviewCommand: '/mcp auth-review',
131
- configCommand: '/mcp config',
132
- workspaceActionIds: [
133
- 'mcp-review',
134
- 'mcp-tools-server',
135
- 'mcp-repair',
136
- 'mcp-config',
137
- 'mcp-add-server',
138
- 'mcp-settings',
139
- ],
140
- confirmationGatedCommands: [
141
- `/mcp trust ${server.name} <constrained|ask-on-risk|blocked> --yes`,
142
- `/mcp role ${server.name} <role> --yes`,
143
- `/mcp quarantine ${server.name} approve <operatorId> --yes`,
144
- `/mcp remove ${server.name} --yes`,
145
- ],
146
- },
119
+ ...(options.includeParameters ? {
120
+ policy: {
121
+ effect: 'read-only',
122
+ values: 'Server posture returns trust, role, connection, quarantine, and tool metadata; env values and secret config values are never returned.',
123
+ mutation: 'MCP add/remove/reload/trust/role/quarantine operations stay explicit confirmation-gated workspace or slash-command flows.',
124
+ allowAll: 'allow-all trust decisions remain routed through Settings -> MCP, not direct command escalation.',
125
+ },
126
+ modelAccess: {
127
+ reviewCommand: '/mcp review',
128
+ serversCommand: '/mcp servers',
129
+ toolsCommand: `/mcp tools ${server.name}`,
130
+ repairCommand: `/mcp repair ${server.name}`,
131
+ authReviewCommand: '/mcp auth-review',
132
+ configCommand: '/mcp config',
133
+ workspaceActionIds: [
134
+ 'mcp-review',
135
+ 'mcp-tools-server',
136
+ 'mcp-repair',
137
+ 'mcp-config',
138
+ 'mcp-add-server',
139
+ 'mcp-settings',
140
+ ],
141
+ confirmationGatedCommands: [
142
+ `/mcp trust ${server.name} <constrained|ask-on-risk|blocked> --yes`,
143
+ `/mcp role ${server.name} <role> --yes`,
144
+ `/mcp quarantine ${server.name} approve <operatorId> --yes`,
145
+ `/mcp remove ${server.name} --yes`,
146
+ ],
147
+ },
148
+ } : {}),
147
149
  };
148
150
  }
149
151
 
@@ -118,12 +118,12 @@ function describeProvider(
118
118
  generateMedia: 'agent_media_generate with confirm:true and explicitUserRequest',
119
119
  ttsSettings: 'agent_harness settings/get_setting/set_setting for tts.provider, tts.voice, tts.llmProvider, and tts.llmModel',
120
120
  },
121
+ policy: {
122
+ effect: 'read-only',
123
+ values: 'Provider posture returns capability, setup, selected, health, and safe environment key names only; secret values and media payloads are never returned.',
124
+ mutation: 'Media generation, voice enable/disable, TTS setting changes, and bundle export stay explicit confirmation-gated tool, setting, workspace, or slash-command flows.',
125
+ },
121
126
  } : {}),
122
- policy: {
123
- effect: 'read-only',
124
- values: 'Provider posture returns capability, setup, selected, health, and safe environment key names only; secret values and media payloads are never returned.',
125
- mutation: 'Media generation, voice enable/disable, TTS setting changes, and bundle export stay explicit confirmation-gated tool, setting, workspace, or slash-command flows.',
126
- },
127
127
  };
128
128
  }
129
129
 
@@ -215,14 +215,14 @@ export async function mediaPostureSummary(context: CommandContext, args: AgentHa
215
215
  returned: filtered.length,
216
216
  total: providers.length,
217
217
  policy: 'Read-only voice/media posture. Media generation, voice enable/disable, TTS setting changes, and bundle export stay confirmation-gated through first-class tools, settings modes, workspace actions, or slash-command mirrors.',
218
- modelAccess: {
218
+ ...(args.includeParameters === true ? { modelAccess: {
219
219
  mediaGenerateTool: 'agent_media_generate',
220
220
  providerCatalogMode: 'media_posture',
221
221
  singleProviderMode: 'media_provider',
222
- ttsProviderPicker: 'open_ui_surface surfaceId:"tts-provider-picker"',
223
- ttsVoicePicker: 'open_ui_surface surfaceId:"tts-voice-picker"',
222
+ ttsProviderPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"tts-provider-picker" confirm:true explicitUserRequest:"..."',
223
+ ttsVoicePicker: 'agent_harness mode:"open_ui_surface" surfaceId:"tts-voice-picker" confirm:true explicitUserRequest:"..."',
224
224
  commands: ['/media providers', '/voice review', '/tts <prompt>', '/image <path>'],
225
- },
225
+ } } : {}),
226
226
  };
227
227
  }
228
228
 
@@ -618,22 +618,40 @@ export function describeConnectedHostCapability(
618
618
  return null;
619
619
  }
620
620
 
621
- export function connectedHostSummary(context: CommandContext, toolRegistry: ToolRegistry): Record<string, unknown> {
621
+ export function connectedHostSummary(
622
+ context: CommandContext,
623
+ toolRegistry: ToolRegistry,
624
+ options: { readonly includeParameters?: boolean } = {},
625
+ ): Record<string, unknown> {
622
626
  const shellPaths = context.workspace.shellPaths;
623
627
  const homeDirectory = shellPaths?.homeDirectory ?? context.platform.configManager.getHomeDirectory() ?? '';
624
628
  const connection = resolveAgentConnectedHostConnection(context.platform.configManager, homeDirectory);
629
+ const routeFamilies = connectedHostRouteFamilies();
630
+ const capabilities = connectedHostCapabilityMap(toolRegistry);
631
+ const blockedCapabilities = blockedConnectedHostCapabilities();
625
632
  return {
626
633
  baseUrl: connection.baseUrl,
627
634
  operatorToken: connection.token ? 'configured' : 'missing',
628
635
  tokenPath: connection.tokenPath,
629
636
  ownership: 'external-connected-host',
630
637
  lifecycle: 'GoodVibes Agent can use public connected-host operator routes, but does not start, stop, restart, install, expose, or mutate the host listener.',
631
- servicePostureMode: 'Use agent_harness mode:"service_posture" for endpoint binding, network-facing posture, issue, and redacted-log diagnostics. Use mode:"service_endpoint" for one endpoint.',
632
- operatorMethodMode: 'Use agent_harness mode:"operator_methods" for the public operator and Agent Knowledge method catalog. Use mode:"operator_method" for one method.',
633
- statusMode: 'Use agent_harness mode:"connected_host_status" for live read-only reachability, SDK compatibility, token posture, and Agent Knowledge route readiness.',
634
- routeFamilies: connectedHostRouteFamilies(),
635
- capabilities: connectedHostCapabilityMap(toolRegistry),
636
- blockedCapabilities: blockedConnectedHostCapabilities(),
638
+ modes: {
639
+ servicePosture: 'service_posture/service_endpoint',
640
+ operatorMethods: 'operator_methods/operator_method',
641
+ liveStatus: 'connected_host_status',
642
+ capabilityDetail: 'connected_host_capability',
643
+ },
644
+ counts: {
645
+ routeFamilies: routeFamilies.length,
646
+ allowedCapabilities: capabilities.length,
647
+ availableCapabilities: capabilities.filter((capability) => capability.available === true).length,
648
+ blockedCapabilities: blockedCapabilities.length,
649
+ },
650
+ ...(options.includeParameters === true ? {
651
+ routeFamilies,
652
+ capabilities,
653
+ blockedCapabilities,
654
+ } : {}),
637
655
  };
638
656
  }
639
657
 
@@ -320,19 +320,19 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
320
320
  commands: route.commands,
321
321
  uiSurfaces: route.uiSurfaces,
322
322
  ...(options.lookup ? { lookup: options.lookup } : {}),
323
- policy: {
324
- effect: 'read-only',
325
- values: 'Model routing posture returns model ids, provider ids, route state, capabilities, and safe setting keys only; provider credentials are never returned.',
326
- mutation: 'Model/provider selection, catalog refresh, favorites, custom provider edits, and route setting changes stay explicit user-facing picker, settings, workspace, or slash-command flows.',
327
- },
328
323
  ...(options.includeParameters ? {
324
+ policy: {
325
+ effect: 'read-only',
326
+ values: 'Model routing posture returns model ids, provider ids, route state, capabilities, and safe setting keys only; provider credentials are never returned.',
327
+ mutation: 'Model/provider selection, catalog refresh, favorites, custom provider edits, and route setting changes stay explicit user-facing picker, settings, workspace, or slash-command flows.',
328
+ },
329
329
  modelAccess: {
330
330
  inspectRouting: 'agent_harness mode:"model_routing"',
331
331
  inspectRoute: 'agent_harness mode:"model_route"',
332
332
  settingRead: 'agent_harness mode:"get_setting"',
333
333
  settingMutation: 'agent_harness mode:"set_setting" confirm:true explicitUserRequest:"..."',
334
- openModelPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"model-picker" confirm:true',
335
- openProviderPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"provider-picker" confirm:true',
334
+ openModelPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"model-picker" confirm:true explicitUserRequest:"..."',
335
+ openProviderPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"provider-picker" confirm:true explicitUserRequest:"..."',
336
336
  },
337
337
  } : {}),
338
338
  };
@@ -350,19 +350,19 @@ function describeModel(model: ModelCandidate, options: { readonly includeParamet
350
350
  pinned: model.pinned,
351
351
  contextWindow: model.contextWindow,
352
352
  reasoningEffort: model.reasoningEffort,
353
- capabilities: model.capabilities,
354
353
  ...(options.lookup ? { lookup: options.lookup } : {}),
355
- policy: {
356
- effect: 'read-only',
357
- mutation: 'Selecting this model stays a visible picker, settings, workspace, or slash-command flow with explicit user request.',
358
- },
359
354
  ...(options.includeParameters ? {
355
+ capabilities: model.capabilities,
356
+ policy: {
357
+ effect: 'read-only',
358
+ mutation: 'Selecting this model stays a visible picker, settings, workspace, or slash-command flow with explicit user request.',
359
+ },
360
360
  modelAccess: {
361
361
  selectModelCommand: `/model ${model.registryKey}`,
362
362
  selectProviderCommand: `/provider ${model.providerId}`,
363
363
  pinCommand: `/pin ${model.registryKey}`,
364
364
  unpinCommand: `/unpin ${model.registryKey}`,
365
- setMainModel: `agent_harness mode:"set_setting" key:"provider.model" value:"${model.registryKey}" confirm:true`,
365
+ setMainModel: `agent_harness mode:"set_setting" key:"provider.model" value:"${model.registryKey}" confirm:true explicitUserRequest:"..."`,
366
366
  },
367
367
  } : {}),
368
368
  };
@@ -433,7 +433,7 @@ export async function modelRoutingSummary(context: CommandContext, args: AgentHa
433
433
  reasoningEffort: modelReasoning(currentModel),
434
434
  capabilities: modelCapabilities(currentModel),
435
435
  pinned: false,
436
- }) : null,
436
+ }, { includeParameters }) : null,
437
437
  },
438
438
  providers: providerIds,
439
439
  routes: filteredRoutes.slice(0, limit).map((route) => describeRoute(route, { includeParameters })),
@@ -25,6 +25,11 @@ function readLimit(value: unknown, fallback: number): number {
25
25
  return Math.max(1, Math.min(500, Math.trunc(parsed)));
26
26
  }
27
27
 
28
+ function previewText(value: string, maxLength = 120): string {
29
+ const normalized = value.replace(/\s+/g, ' ').trim();
30
+ return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 1).trimEnd()}...`;
31
+ }
32
+
28
33
  function modelToolSearchText(tool: HarnessModelToolDefinition): string {
29
34
  return [
30
35
  tool.name,
@@ -45,7 +50,7 @@ function modelToolLookupFromArgs(args: AgentHarnessModelToolCatalogArgs): { read
45
50
  function describeModelTool(tool: HarnessModelToolDefinition, options: { readonly includeParameters?: boolean; readonly lookup?: Record<string, unknown> } = {}): Record<string, unknown> {
46
51
  return {
47
52
  name: tool.name,
48
- description: tool.description,
53
+ ...(options.includeParameters ? { description: tool.description } : { summary: previewText(tool.description) }),
49
54
  sideEffects: tool.sideEffects ?? [],
50
55
  concurrency: tool.concurrency ?? 'parallel',
51
56
  supportsProgress: tool.supportsProgress ?? false,
@@ -58,7 +63,7 @@ function describeModelTool(tool: HarnessModelToolDefinition, options: { readonly
58
63
  function describeModelToolCandidates(tools: readonly HarnessModelToolDefinition[]): readonly Record<string, unknown>[] {
59
64
  return tools.slice(0, 8).map((tool) => ({
60
65
  toolName: tool.name,
61
- description: tool.description,
66
+ summary: previewText(tool.description),
62
67
  sideEffects: tool.sideEffects ?? [],
63
68
  }));
64
69
  }