@clawnet/template-minimal 0.0.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.
Files changed (67) hide show
  1. package/.agents/skills/claude-agent-sdk/.claude-plugin/plugin.json +13 -0
  2. package/.agents/skills/claude-agent-sdk/SKILL.md +954 -0
  3. package/.agents/skills/claude-agent-sdk/references/mcp-servers-guide.md +387 -0
  4. package/.agents/skills/claude-agent-sdk/references/permissions-guide.md +429 -0
  5. package/.agents/skills/claude-agent-sdk/references/query-api-reference.md +437 -0
  6. package/.agents/skills/claude-agent-sdk/references/session-management.md +419 -0
  7. package/.agents/skills/claude-agent-sdk/references/subagents-patterns.md +464 -0
  8. package/.agents/skills/claude-agent-sdk/references/top-errors.md +503 -0
  9. package/.agents/skills/claude-agent-sdk/rules/claude-agent-sdk.md +96 -0
  10. package/.agents/skills/claude-agent-sdk/scripts/check-versions.sh +55 -0
  11. package/.agents/skills/claude-agent-sdk/templates/basic-query.ts +55 -0
  12. package/.agents/skills/claude-agent-sdk/templates/custom-mcp-server.ts +161 -0
  13. package/.agents/skills/claude-agent-sdk/templates/error-handling.ts +283 -0
  14. package/.agents/skills/claude-agent-sdk/templates/filesystem-settings.ts +211 -0
  15. package/.agents/skills/claude-agent-sdk/templates/multi-agent-workflow.ts +318 -0
  16. package/.agents/skills/claude-agent-sdk/templates/package.json +30 -0
  17. package/.agents/skills/claude-agent-sdk/templates/permission-control.ts +211 -0
  18. package/.agents/skills/claude-agent-sdk/templates/query-with-tools.ts +54 -0
  19. package/.agents/skills/claude-agent-sdk/templates/session-management.ts +151 -0
  20. package/.agents/skills/claude-agent-sdk/templates/subagents-orchestration.ts +166 -0
  21. package/.agents/skills/claude-agent-sdk/templates/tsconfig.json +22 -0
  22. package/.claude/settings.local.json +70 -0
  23. package/.claude/skills/moltbook-example/SKILL.md +79 -0
  24. package/.claude/skills/post/SKILL.md +130 -0
  25. package/.env.example +4 -0
  26. package/.vercel/README.txt +11 -0
  27. package/.vercel/project.json +1 -0
  28. package/AGENTS.md +114 -0
  29. package/CLAUDE.md +532 -0
  30. package/README.md +44 -0
  31. package/api/index.ts +3 -0
  32. package/biome.json +14 -0
  33. package/clark_avatar.jpeg +0 -0
  34. package/package.json +21 -0
  35. package/scripts/wake.ts +38 -0
  36. package/skills/clawbook/HEARTBEAT.md +142 -0
  37. package/skills/clawbook/SKILL.md +219 -0
  38. package/skills/moltbook-example/SKILL.md +79 -0
  39. package/skills/moltbook-example/bot/index.ts +61 -0
  40. package/src/agent/prompts.ts +98 -0
  41. package/src/agent/runner.ts +526 -0
  42. package/src/agent/tool-definitions.ts +1151 -0
  43. package/src/agent-options.ts +14 -0
  44. package/src/bot-identity.ts +41 -0
  45. package/src/constants.ts +15 -0
  46. package/src/handlers/heartbeat.ts +21 -0
  47. package/src/handlers/openai-compat.ts +95 -0
  48. package/src/handlers/post.ts +21 -0
  49. package/src/identity.ts +83 -0
  50. package/src/index.ts +30 -0
  51. package/src/middleware/cron-auth.ts +53 -0
  52. package/src/middleware/sigma-auth.ts +147 -0
  53. package/src/runs.ts +49 -0
  54. package/tests/agent/prompts.test.ts +172 -0
  55. package/tests/agent/runner.test.ts +353 -0
  56. package/tests/agent/tool-definitions.test.ts +171 -0
  57. package/tests/constants.test.ts +24 -0
  58. package/tests/handlers/openai-compat.test.ts +128 -0
  59. package/tests/handlers.test.ts +133 -0
  60. package/tests/identity.test.ts +66 -0
  61. package/tests/index.test.ts +108 -0
  62. package/tests/middleware/cron-auth.test.ts +99 -0
  63. package/tests/middleware/sigma-auth.test.ts +198 -0
  64. package/tests/runs.test.ts +56 -0
  65. package/tests/skill.test.ts +71 -0
  66. package/tsconfig.json +14 -0
  67. package/vercel.json +9 -0
@@ -0,0 +1,161 @@
1
+ import { query, createSdkMcpServer, tool } from "@anthropic-ai/claude-agent-sdk";
2
+ import { z } from "zod";
3
+
4
+ /**
5
+ * Custom MCP Server Template
6
+ *
7
+ * Demonstrates:
8
+ * - Creating in-process MCP server
9
+ * - Defining tools with Zod schemas
10
+ * - Multiple tools in one server
11
+ * - Error handling in tools
12
+ */
13
+
14
+ // Define a custom MCP server with multiple tools
15
+ const weatherServer = createSdkMcpServer({
16
+ name: "weather-service",
17
+ version: "1.0.0",
18
+ tools: [
19
+ tool(
20
+ "get_weather",
21
+ "Get current weather for a location",
22
+ {
23
+ location: z.string().describe("City name or coordinates"),
24
+ units: z.enum(["celsius", "fahrenheit"]).default("celsius")
25
+ },
26
+ async (args) => {
27
+ try {
28
+ // Simulate API call
29
+ const response = await fetch(
30
+ `https://api.weather.com/v1/current?location=${args.location}&units=${args.units}`
31
+ );
32
+ const data = await response.json();
33
+
34
+ return {
35
+ content: [{
36
+ type: "text",
37
+ text: `Temperature: ${data.temp}° ${args.units}\nConditions: ${data.conditions}\nHumidity: ${data.humidity}%`
38
+ }]
39
+ };
40
+ } catch (error) {
41
+ return {
42
+ content: [{
43
+ type: "text",
44
+ text: `Error fetching weather: ${error.message}`
45
+ }],
46
+ isError: true
47
+ };
48
+ }
49
+ }
50
+ ),
51
+ tool(
52
+ "get_forecast",
53
+ "Get weather forecast for next 7 days",
54
+ {
55
+ location: z.string(),
56
+ days: z.number().min(1).max(7).default(7)
57
+ },
58
+ async (args) => {
59
+ // Simulated forecast data
60
+ return {
61
+ content: [{
62
+ type: "text",
63
+ text: `7-day forecast for ${args.location}: Mostly sunny with temperatures ranging from 15-25°C`
64
+ }]
65
+ };
66
+ }
67
+ )
68
+ ]
69
+ });
70
+
71
+ // Database tools server
72
+ const databaseServer = createSdkMcpServer({
73
+ name: "database",
74
+ version: "1.0.0",
75
+ tools: [
76
+ tool(
77
+ "query_users",
78
+ "Query user records from the database",
79
+ {
80
+ email: z.string().email().optional(),
81
+ limit: z.number().min(1).max(100).default(10),
82
+ offset: z.number().min(0).default(0)
83
+ },
84
+ async (args) => {
85
+ // Simulated database query
86
+ const results = [
87
+ { id: 1, email: "user1@example.com", name: "User 1" },
88
+ { id: 2, email: "user2@example.com", name: "User 2" }
89
+ ];
90
+
91
+ return {
92
+ content: [{
93
+ type: "text",
94
+ text: JSON.stringify(results, null, 2)
95
+ }]
96
+ };
97
+ }
98
+ ),
99
+ tool(
100
+ "calculate",
101
+ "Perform mathematical calculations",
102
+ {
103
+ expression: z.string().describe("Mathematical expression to evaluate"),
104
+ precision: z.number().min(0).max(10).default(2)
105
+ },
106
+ async (args) => {
107
+ try {
108
+ // In production, use a proper math parser (e.g., mathjs)
109
+ const result = eval(args.expression);
110
+ const rounded = Number(result.toFixed(args.precision));
111
+
112
+ return {
113
+ content: [{
114
+ type: "text",
115
+ text: `Result: ${rounded}`
116
+ }]
117
+ };
118
+ } catch (error) {
119
+ return {
120
+ content: [{
121
+ type: "text",
122
+ text: `Invalid expression: ${error.message}`
123
+ }],
124
+ isError: true
125
+ };
126
+ }
127
+ }
128
+ )
129
+ ]
130
+ });
131
+
132
+ // Use custom tools in query
133
+ async function useCustomTools() {
134
+ const response = query({
135
+ prompt: "What's the weather in San Francisco? Also query users with gmail addresses and calculate 15% tip on $85.50",
136
+ options: {
137
+ model: "claude-sonnet-4-5",
138
+ mcpServers: {
139
+ "weather-service": weatherServer,
140
+ "database": databaseServer
141
+ },
142
+ allowedTools: [
143
+ "mcp__weather-service__get_weather",
144
+ "mcp__weather-service__get_forecast",
145
+ "mcp__database__query_users",
146
+ "mcp__database__calculate"
147
+ ]
148
+ }
149
+ });
150
+
151
+ for await (const message of response) {
152
+ if (message.type === 'assistant') {
153
+ console.log('Assistant:', message.content);
154
+ } else if (message.type === 'tool_call') {
155
+ console.log(`\n🔧 ${message.tool_name}:`, message.input);
156
+ }
157
+ }
158
+ }
159
+
160
+ // Run
161
+ useCustomTools().catch(console.error);
@@ -0,0 +1,283 @@
1
+ import { query } from "@anthropic-ai/claude-agent-sdk";
2
+
3
+ /**
4
+ * Error Handling Template
5
+ *
6
+ * Demonstrates:
7
+ * - SDK error handling
8
+ * - Message-level error handling
9
+ * - Retry strategies
10
+ * - Graceful degradation
11
+ */
12
+
13
+ // Example 1: Basic Error Handling
14
+ async function basicErrorHandling() {
15
+ try {
16
+ const response = query({
17
+ prompt: "Analyze and refactor code",
18
+ options: {
19
+ model: "claude-sonnet-4-5",
20
+ workingDirectory: "/path/to/project"
21
+ }
22
+ });
23
+
24
+ for await (const message of response) {
25
+ switch (message.type) {
26
+ case 'assistant':
27
+ console.log('Assistant:', message.content);
28
+ break;
29
+
30
+ case 'error':
31
+ console.error('Agent error:', message.error.message);
32
+ if (message.error.type === 'permission_denied') {
33
+ console.log('Permission denied for:', message.error.tool);
34
+ // Handle permission errors gracefully
35
+ }
36
+ break;
37
+ }
38
+ }
39
+ } catch (error) {
40
+ console.error('Fatal error:', error);
41
+
42
+ // Handle specific error codes
43
+ if (error.code === 'CLI_NOT_FOUND') {
44
+ console.error('Claude Code CLI not installed');
45
+ console.error('Install: npm install -g @anthropic-ai/claude-code');
46
+ } else if (error.code === 'AUTHENTICATION_FAILED') {
47
+ console.error('Invalid API key. Check ANTHROPIC_API_KEY');
48
+ } else if (error.code === 'RATE_LIMIT_EXCEEDED') {
49
+ console.error('Rate limit exceeded. Retry after delay.');
50
+ } else if (error.code === 'CONTEXT_LENGTH_EXCEEDED') {
51
+ console.error('Context too large. Use session compaction.');
52
+ }
53
+ }
54
+ }
55
+
56
+ // Example 2: Retry with Exponential Backoff
57
+ async function retryWithBackoff(
58
+ prompt: string,
59
+ maxRetries = 3,
60
+ baseDelay = 1000
61
+ ): Promise<void> {
62
+ for (let attempt = 0; attempt < maxRetries; attempt++) {
63
+ try {
64
+ const response = query({
65
+ prompt,
66
+ options: {
67
+ model: "claude-sonnet-4-5"
68
+ }
69
+ });
70
+
71
+ for await (const message of response) {
72
+ if (message.type === 'assistant') {
73
+ console.log(message.content);
74
+ }
75
+ }
76
+
77
+ return; // Success, exit
78
+ } catch (error) {
79
+ if (error.code === 'RATE_LIMIT_EXCEEDED' && attempt < maxRetries - 1) {
80
+ const delay = baseDelay * Math.pow(2, attempt);
81
+ console.log(`Rate limited. Retrying in ${delay}ms...`);
82
+ await new Promise(resolve => setTimeout(resolve, delay));
83
+ } else {
84
+ throw error; // Re-throw if not rate limit or final attempt
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ // Example 3: Graceful Degradation
91
+ async function gracefulDegradation(prompt: string) {
92
+ // Try with full capabilities first
93
+ try {
94
+ console.log('Attempting with Sonnet model...');
95
+ const response = query({
96
+ prompt,
97
+ options: {
98
+ model: "claude-sonnet-4-5",
99
+ allowedTools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
100
+ }
101
+ });
102
+
103
+ for await (const message of response) {
104
+ if (message.type === 'assistant') {
105
+ console.log(message.content);
106
+ }
107
+ }
108
+ } catch (error) {
109
+ console.warn('Sonnet failed, falling back to Haiku...');
110
+
111
+ // Fallback to faster/cheaper model with limited tools
112
+ try {
113
+ const response = query({
114
+ prompt,
115
+ options: {
116
+ model: "haiku",
117
+ allowedTools: ["Read", "Grep", "Glob"] // Read-only
118
+ }
119
+ });
120
+
121
+ for await (const message of response) {
122
+ if (message.type === 'assistant') {
123
+ console.log(message.content);
124
+ }
125
+ }
126
+ } catch (fallbackError) {
127
+ console.error('All attempts failed:', fallbackError);
128
+ throw fallbackError;
129
+ }
130
+ }
131
+ }
132
+
133
+ // Example 4: Comprehensive Error Handler
134
+ async function comprehensiveErrorHandling() {
135
+ const errors: Array<{ type: string; message: string; timestamp: Date }> = [];
136
+
137
+ try {
138
+ const response = query({
139
+ prompt: "Complex multi-step task",
140
+ options: {
141
+ model: "claude-sonnet-4-5",
142
+ permissionMode: "default"
143
+ }
144
+ });
145
+
146
+ for await (const message of response) {
147
+ switch (message.type) {
148
+ case 'assistant':
149
+ console.log('✅ Assistant:', message.content);
150
+ break;
151
+
152
+ case 'tool_call':
153
+ console.log(`🔧 Executing: ${message.tool_name}`);
154
+ break;
155
+
156
+ case 'tool_result':
157
+ console.log(`✅ ${message.tool_name} completed`);
158
+ break;
159
+
160
+ case 'error':
161
+ console.error('❌ Error:', message.error.message);
162
+ errors.push({
163
+ type: message.error.type,
164
+ message: message.error.message,
165
+ timestamp: new Date()
166
+ });
167
+
168
+ // Handle different error types
169
+ if (message.error.type === 'permission_denied') {
170
+ console.log('→ Permission was denied, continuing with limited access');
171
+ } else if (message.error.type === 'tool_execution_failed') {
172
+ console.log('→ Tool failed, attempting alternative approach');
173
+ }
174
+ break;
175
+ }
176
+ }
177
+ } catch (error) {
178
+ console.error('💥 Fatal error:', error);
179
+
180
+ // Log error details
181
+ errors.push({
182
+ type: error.code || 'UNKNOWN',
183
+ message: error.message,
184
+ timestamp: new Date()
185
+ });
186
+
187
+ // Specific handlers
188
+ if (error.code === 'AUTHENTICATION_FAILED') {
189
+ console.error('→ Check your ANTHROPIC_API_KEY environment variable');
190
+ console.error('→ Visit https://console.anthropic.com/ for API keys');
191
+ } else if (error.code === 'RATE_LIMIT_EXCEEDED') {
192
+ console.error('→ Rate limit exceeded');
193
+ console.error('→ Implement exponential backoff or reduce request frequency');
194
+ } else if (error.code === 'CONTEXT_LENGTH_EXCEEDED') {
195
+ console.error('→ Context too large');
196
+ console.error('→ Consider using session management or reducing prompt size');
197
+ } else if (error.code === 'CLI_NOT_FOUND') {
198
+ console.error('→ Claude Code CLI not found');
199
+ console.error('→ Install: npm install -g @anthropic-ai/claude-code');
200
+ }
201
+
202
+ throw error;
203
+ } finally {
204
+ // Always log error summary
205
+ if (errors.length > 0) {
206
+ console.log('\n\n=== Error Summary ===');
207
+ errors.forEach(err => {
208
+ console.log(`${err.timestamp.toISOString()} - ${err.type}: ${err.message}`);
209
+ });
210
+ }
211
+ }
212
+ }
213
+
214
+ // Example 5: Circuit Breaker Pattern
215
+ class CircuitBreaker {
216
+ private failures = 0;
217
+ private lastFailureTime?: Date;
218
+ private readonly threshold = 3;
219
+ private readonly resetTimeout = 60000; // 1 minute
220
+
221
+ async execute(fn: () => Promise<void>): Promise<void> {
222
+ // Check if circuit is open
223
+ if (this.isOpen()) {
224
+ throw new Error('Circuit breaker is OPEN. Too many failures.');
225
+ }
226
+
227
+ try {
228
+ await fn();
229
+ this.onSuccess();
230
+ } catch (error) {
231
+ this.onFailure();
232
+ throw error;
233
+ }
234
+ }
235
+
236
+ private isOpen(): boolean {
237
+ if (this.failures >= this.threshold) {
238
+ const now = new Date();
239
+ if (this.lastFailureTime &&
240
+ now.getTime() - this.lastFailureTime.getTime() < this.resetTimeout) {
241
+ return true;
242
+ }
243
+ // Reset after timeout
244
+ this.failures = 0;
245
+ }
246
+ return false;
247
+ }
248
+
249
+ private onSuccess() {
250
+ this.failures = 0;
251
+ this.lastFailureTime = undefined;
252
+ }
253
+
254
+ private onFailure() {
255
+ this.failures++;
256
+ this.lastFailureTime = new Date();
257
+ console.warn(`Circuit breaker: ${this.failures}/${this.threshold} failures`);
258
+ }
259
+ }
260
+
261
+ async function useCircuitBreaker() {
262
+ const breaker = new CircuitBreaker();
263
+
264
+ try {
265
+ await breaker.execute(async () => {
266
+ const response = query({
267
+ prompt: "Perform task",
268
+ options: { model: "sonnet" }
269
+ });
270
+
271
+ for await (const message of response) {
272
+ if (message.type === 'assistant') {
273
+ console.log(message.content);
274
+ }
275
+ }
276
+ });
277
+ } catch (error) {
278
+ console.error('Circuit breaker prevented execution or task failed:', error);
279
+ }
280
+ }
281
+
282
+ // Run
283
+ comprehensiveErrorHandling().catch(console.error);
@@ -0,0 +1,211 @@
1
+ import { query } from "@anthropic-ai/claude-agent-sdk";
2
+
3
+ /**
4
+ * Filesystem Settings Template
5
+ *
6
+ * Demonstrates:
7
+ * - Loading settings from user, project, local
8
+ * - Settings priority and merging
9
+ * - Isolated vs configured execution
10
+ * - Loading CLAUDE.md project instructions
11
+ */
12
+
13
+ // Example 1: Load All Settings (Legacy Behavior)
14
+ async function loadAllSettings() {
15
+ const response = query({
16
+ prompt: "Build a new feature following project conventions",
17
+ options: {
18
+ model: "claude-sonnet-4-5",
19
+ settingSources: ["user", "project", "local"]
20
+ // Loads:
21
+ // 1. ~/.claude/settings.json (user)
22
+ // 2. .claude/settings.json (project)
23
+ // 3. .claude/settings.local.json (local overrides)
24
+ //
25
+ // Priority (highest first):
26
+ // 1. Programmatic options (this config)
27
+ // 2. Local settings
28
+ // 3. Project settings
29
+ // 4. User settings
30
+ }
31
+ });
32
+
33
+ for await (const message of response) {
34
+ if (message.type === 'assistant') {
35
+ console.log(message.content);
36
+ }
37
+ }
38
+ }
39
+
40
+ // Example 2: Project Settings Only (CI/CD Pattern)
41
+ async function projectSettingsOnly() {
42
+ const response = query({
43
+ prompt: "Run automated code review",
44
+ options: {
45
+ model: "claude-sonnet-4-5",
46
+ settingSources: ["project"]
47
+ // Only .claude/settings.json
48
+ // Ignores user and local settings
49
+ // Ensures consistent behavior in CI/CD
50
+ }
51
+ });
52
+
53
+ for await (const message of response) {
54
+ if (message.type === 'assistant') {
55
+ console.log(message.content);
56
+ }
57
+ }
58
+ }
59
+
60
+ // Example 3: No Filesystem Settings (Fully Isolated)
61
+ async function isolatedExecution() {
62
+ const response = query({
63
+ prompt: "Analyze this code snippet",
64
+ options: {
65
+ model: "claude-sonnet-4-5",
66
+ settingSources: [], // Empty = no filesystem settings
67
+ workingDirectory: "/tmp/sandbox",
68
+ allowedTools: ["Read", "Grep", "Glob"],
69
+ systemPrompt: "You are a code analyzer."
70
+ // Fully isolated, no filesystem dependencies
71
+ // Perfect for sandboxed/containerized environments
72
+ }
73
+ });
74
+
75
+ for await (const message of response) {
76
+ if (message.type === 'assistant') {
77
+ console.log(message.content);
78
+ }
79
+ }
80
+ }
81
+
82
+ // Example 4: Hybrid Approach (Project + Programmatic)
83
+ async function hybridConfiguration() {
84
+ const response = query({
85
+ prompt: "Implement user authentication system",
86
+ options: {
87
+ model: "claude-sonnet-4-5",
88
+ settingSources: ["project"], // Load CLAUDE.md and project settings
89
+ systemPrompt: "Follow security best practices and company coding standards.",
90
+ agents: {
91
+ "security-checker": {
92
+ description: "Security validation specialist",
93
+ prompt: "Validate all security implementations against OWASP guidelines.",
94
+ tools: ["Read", "Grep"],
95
+ model: "sonnet"
96
+ }
97
+ },
98
+ allowedTools: ["Read", "Write", "Edit", "Grep", "Glob"]
99
+ // Project settings + programmatic overrides
100
+ // Programmatic settings always win
101
+ }
102
+ });
103
+
104
+ for await (const message of response) {
105
+ if (message.type === 'assistant') {
106
+ console.log(message.content);
107
+ }
108
+ }
109
+ }
110
+
111
+ // Example 5: Loading CLAUDE.md Project Instructions
112
+ async function loadProjectInstructions() {
113
+ const response = query({
114
+ prompt: "Implement new feature according to project guidelines",
115
+ options: {
116
+ model: "claude-sonnet-4-5",
117
+ systemPrompt: {
118
+ type: 'preset',
119
+ preset: 'claude_code' // Required to use CLAUDE.md
120
+ },
121
+ settingSources: ["project"], // Reads CLAUDE.md from project directory
122
+ workingDirectory: process.cwd()
123
+ }
124
+ });
125
+
126
+ for await (const message of response) {
127
+ if (message.type === 'assistant') {
128
+ console.log(message.content);
129
+ }
130
+ }
131
+ }
132
+
133
+ // Example 6: Environment-Specific Settings
134
+ async function environmentSpecificSettings(
135
+ environment: 'development' | 'staging' | 'production'
136
+ ) {
137
+ let settingSources: Array<'user' | 'project' | 'local'>;
138
+ let permissionMode: 'default' | 'acceptEdits' | 'bypassPermissions';
139
+
140
+ switch (environment) {
141
+ case 'development':
142
+ settingSources = ["user", "project", "local"];
143
+ permissionMode = "acceptEdits";
144
+ break;
145
+
146
+ case 'staging':
147
+ settingSources = ["project"];
148
+ permissionMode = "default";
149
+ break;
150
+
151
+ case 'production':
152
+ settingSources = ["project"];
153
+ permissionMode = "default";
154
+ break;
155
+ }
156
+
157
+ const response = query({
158
+ prompt: "Deploy application",
159
+ options: {
160
+ model: "claude-sonnet-4-5",
161
+ settingSources,
162
+ permissionMode,
163
+ workingDirectory: process.cwd()
164
+ }
165
+ });
166
+
167
+ for await (const message of response) {
168
+ if (message.type === 'assistant') {
169
+ console.log(message.content);
170
+ }
171
+ }
172
+ }
173
+
174
+ // Settings File Examples:
175
+
176
+ /**
177
+ * ~/.claude/settings.json (User Settings)
178
+ * {
179
+ * "model": "claude-sonnet-4-5",
180
+ * "allowedTools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
181
+ * "permissionMode": "default"
182
+ * }
183
+ */
184
+
185
+ /**
186
+ * .claude/settings.json (Project Settings - version controlled)
187
+ * {
188
+ * "model": "claude-sonnet-4-5",
189
+ * "allowedTools": ["Read", "Write", "Edit", "Grep", "Glob"],
190
+ * "disallowedTools": ["Bash"],
191
+ * "agents": {
192
+ * "code-reviewer": {
193
+ * "description": "Review code for quality",
194
+ * "prompt": "You review code for best practices.",
195
+ * "tools": ["Read", "Grep"],
196
+ * "model": "haiku"
197
+ * }
198
+ * }
199
+ * }
200
+ */
201
+
202
+ /**
203
+ * .claude/settings.local.json (Local Overrides - gitignored)
204
+ * {
205
+ * "permissionMode": "acceptEdits",
206
+ * "allowedTools": ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
207
+ * }
208
+ */
209
+
210
+ // Run
211
+ hybridConfiguration().catch(console.error);