@botbotgo/agent-harness 0.0.18 → 0.0.20

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
@@ -1,11 +1,19 @@
1
1
  # @botbotgo/agent-harness
2
2
 
3
- `@botbotgo/agent-harness` is a TypeScript framework for running local agent workspaces with declarative config, reusable tools, reusable skills, and configurable host-agent routing.
3
+ ## Slogan
4
4
 
5
- It is designed for two common use cases:
5
+ Declarative agent workspaces for LangChain v1 and DeepAgents.
6
6
 
7
- - build a reusable agent runtime package and publish it to npm
8
- - build an application workspace that ships its own agents, tools, skills, and model config
7
+ ## Product Overview
8
+
9
+ `@botbotgo/agent-harness` is a TypeScript framework for loading a local workspace from disk, compiling it into runnable agent bindings, and executing requests through either a LangChain v1 path or a DeepAgent path.
10
+
11
+ The framework is workspace-first:
12
+
13
+ - agents are declared in YAML
14
+ - tools and skills are discovered from `resources/`
15
+ - workspace-wide behavior is declared in `config/workspace.yaml`
16
+ - agent bootstrap context is declared in `config/agent-context.md`
9
17
 
10
18
  The public API stays intentionally small:
11
19
 
@@ -15,25 +23,6 @@ The public API stays intentionally small:
15
23
  - `getThread(...)`
16
24
  - `stop(...)`
17
25
 
18
- ## Product Overview
19
-
20
- Agent Harness loads a workspace from disk, compiles its config into runnable agent bindings, and executes requests through either a lightweight LangChain path or a DeepAgent path.
21
-
22
- Out of the box, the framework supports:
23
-
24
- - workspace loading from a directory root
25
- - declarative `Model`, `EmbeddingModel`, `VectorStore`, `LangChainAgent`, `DeepAgent`, and `Runtime` objects
26
- - host-agent routing between a direct path and an orchestration path
27
- - tool loading from resource packages and external sources
28
- - skill discovery from filesystem roots
29
- - subagent discovery from filesystem roots
30
- - thread persistence, run history, and resumable state
31
-
32
- The default package config in this repo shows the intended model:
33
-
34
- - `direct`: low-latency host for simple one-step requests
35
- - `orchestra`: default host for multi-step work, tools, skills, and delegation
36
-
37
26
  ## Quick Start
38
27
 
39
28
  Install the package:
@@ -42,14 +31,14 @@ Install the package:
42
31
  npm install @botbotgo/agent-harness
43
32
  ```
44
33
 
45
- Create a workspace with at least:
34
+ Create a workspace:
46
35
 
47
36
  ```text
48
37
  your-workspace/
49
- AGENTS.md
50
38
  config/
39
+ agent-context.md
40
+ workspace.yaml
51
41
  models.yaml
52
- runtime.yaml
53
42
  agents/
54
43
  direct.yaml
55
44
  orchestra.yaml
@@ -77,29 +66,23 @@ try {
77
66
  }
78
67
  ```
79
68
 
80
- If you want the framework to choose the host agent automatically, pass `agentId: "auto"` when your workspace has runtime routing configured.
81
-
82
- ## How To Use
83
-
84
- There are two common ways to use the framework.
85
-
86
- ### 1. Use It As A Library
87
-
88
- Load a workspace from disk and run requests through the public API.
89
-
90
- #### SDK Surface
69
+ ## Feature List
91
70
 
92
- The SDK is intentionally small:
71
+ - Declarative `Model`, `EmbeddingModel`, `VectorStore`, `LangChainAgent`, `DeepAgent`, and `Runtime` objects
72
+ - Workspace loading from disk with framework defaults and workspace overrides
73
+ - LangChain v1 agents for lightweight tool-calling flows
74
+ - DeepAgents for planning, filesystem-backed execution, subagents, skills, and long-term memory
75
+ - Resource package loading from `resources/tools/` and `resources/skills/`
76
+ - Host-agent routing between a direct lane and an orchestration lane
77
+ - Persistent thread state, approvals, run history, and resumable execution
78
+ - Store-backed `/memories/*` long-term memory
79
+ - Background checkpoint maintenance for `SqliteSaver`
93
80
 
94
- - `createAgentHarness(...)`: load a workspace and initialize the runtime
95
- - `run(...)`: start a new run or answer an approval request
96
- - `subscribe(...)`: observe runtime events for logging or UI updates
97
- - `getThread(...)`: fetch persisted thread state and messages
98
- - `stop(...)`: release runtime resources when your process is done
81
+ ## How To Use
99
82
 
100
- #### Create A Harness From A Workspace Path
83
+ ### Create A Harness
101
84
 
102
- This is the standard entry point. Pass the workspace root and let the harness load `AGENTS.md`, `config/`, resource sources, skills, tools, and agent bindings from disk.
85
+ Pass a workspace root:
103
86
 
104
87
  ```ts
105
88
  import { createAgentHarness } from "@botbotgo/agent-harness";
@@ -107,519 +90,133 @@ import { createAgentHarness } from "@botbotgo/agent-harness";
107
90
  const harness = await createAgentHarness("/absolute/path/to/workspace");
108
91
  ```
109
92
 
110
- If you omit the path, the SDK uses `process.cwd()`:
93
+ Or pass a prebuilt `WorkspaceBundle`:
111
94
 
112
95
  ```ts
113
- const harness = await createAgentHarness();
114
- ```
115
-
116
- #### Create A Harness From A Prebuilt WorkspaceBundle
117
-
118
- If your application compiles a workspace in code, or you want tighter control in tests, you can pass a `WorkspaceBundle` directly.
119
-
120
- ```ts
121
- import { createAgentHarness } from "@botbotgo/agent-harness";
122
-
123
96
  const harness = await createAgentHarness(workspaceBundle);
124
97
  ```
125
98
 
126
- #### Run A Simple Request
127
-
128
- Use `run(...)` with an `agentId` and plain-text `input`. The return value includes:
129
-
130
- - `threadId`: stable conversation id
131
- - `runId`: the current execution id
132
- - `state`: final state such as `completed` or `waiting_for_approval`
133
- - `output`: final visible model output
99
+ ### Run A Request
134
100
 
135
101
  ```ts
136
- import { createAgentHarness, run, stop } from "@botbotgo/agent-harness";
102
+ import { run } from "@botbotgo/agent-harness";
137
103
 
138
- const harness = await createAgentHarness("/absolute/path/to/workspace");
104
+ const result = await run(harness, {
105
+ agentId: "direct",
106
+ input: "Explain the available agents in this workspace.",
107
+ });
108
+ ```
139
109
 
140
- try {
141
- const result = await run(harness, {
142
- agentId: "direct",
143
- input: "Summarize what this workspace is for.",
144
- });
110
+ The result includes:
145
111
 
146
- console.log(result.threadId);
147
- console.log(result.runId);
148
- console.log(result.state);
149
- console.log(result.output);
150
- } finally {
151
- await stop(harness);
152
- }
153
- ```
112
+ - `threadId`
113
+ - `runId`
114
+ - `state`
115
+ - `output`
154
116
 
155
- #### Let The Harness Choose The Host Agent
117
+ ### Let The Harness Choose The Host Agent
156
118
 
157
- If your workspace defines runtime routing, use `agentId: "auto"` to let the harness choose between host agents such as `direct` and `orchestra`.
119
+ Use `agentId: "auto"` when your workspace defines routing:
158
120
 
159
121
  ```ts
160
122
  const result = await run(harness, {
161
123
  agentId: "auto",
162
- input: "Inspect this repository and explain how the release flow works.",
124
+ input: "Inspect this repository and explain the release flow.",
163
125
  });
164
126
  ```
165
127
 
166
- Use this mode when your application should not hardcode the host agent choice.
167
-
168
- #### Stream Chunks And Runtime Events
169
-
170
- `run(...)` accepts listeners for streamed output and runtime activity. This is the main SDK path for CLIs, chat UIs, and debug logging.
128
+ ### Stream Output And Events
171
129
 
172
130
  ```ts
173
131
  const result = await run(harness, {
174
132
  agentId: "orchestra",
175
- input: "Inspect the workspace and explain the available agents.",
133
+ input: "Inspect the workspace and explain the available tools.",
176
134
  listeners: {
177
135
  onChunk(chunk) {
178
136
  process.stdout.write(chunk);
179
137
  },
180
138
  onEvent(event) {
181
- console.log("event:", event.eventType, event.payload);
182
- },
183
- onStep(step) {
184
- console.log("step:", step);
185
- },
186
- onToolResult(item) {
187
- console.log("tool:", item.toolName, item.output);
139
+ console.log(event.eventType, event.payload);
188
140
  },
189
141
  },
190
142
  });
191
143
  ```
192
144
 
193
- Listener usage by type:
194
-
195
- - `onChunk`: streamed user-visible response text
196
- - `onEvent`: raw runtime events
197
- - `onStep`: higher-level execution step messages
198
- - `onToolResult`: completed tool outputs
199
- - `onReasoning`: reasoning-channel text when available from the runtime
200
-
201
- #### Subscribe To Global Harness Events
202
-
203
- Use `subscribe(...)` when you want a process-wide event feed rather than per-run listeners.
204
-
205
- ```ts
206
- import { subscribe } from "@botbotgo/agent-harness";
207
-
208
- const unsubscribe = subscribe(harness, (event) => {
209
- console.log(event.threadId, event.runId, event.eventType);
210
- });
211
-
212
- // later
213
- unsubscribe();
214
- ```
215
-
216
- This is useful when one process is handling multiple runs or updating a central UI.
217
-
218
- #### Continue An Existing Thread
219
-
220
- Pass an existing `threadId` to keep the conversation on the same persisted thread.
221
-
222
- ```ts
223
- const first = await run(harness, {
224
- agentId: "direct",
225
- input: "Remember that the release branch is master.",
226
- });
227
-
228
- const second = await run(harness, {
229
- agentId: "direct",
230
- threadId: first.threadId,
231
- input: "What did I just tell you about the release branch?",
232
- });
233
- ```
234
-
235
- #### Read Back Thread State
236
-
237
- Use `getThread(...)` to fetch persisted thread data after a run completes.
145
+ ### Read Back Thread State
238
146
 
239
147
  ```ts
240
148
  import { getThread } from "@botbotgo/agent-harness";
241
149
 
242
150
  const thread = await getThread(harness, result.threadId);
243
-
244
- console.log(thread?.threadId);
245
151
  console.log(thread?.messages.at(-1)?.content);
246
152
  ```
247
153
 
248
- Use this when your app needs to reopen a conversation, render history, or inspect the latest assistant message.
249
-
250
- #### Handle Approval Or Interrupt Flows
251
-
252
- Some runs can pause with `state: "waiting_for_approval"`. In that case, call `run(...)` again with the thread or approval decision payload instead of starting a new request.
253
-
254
- ```ts
255
- const pending = await run(harness, {
256
- agentId: "orchestra",
257
- input: "Run the protected action if approval is required.",
258
- });
259
-
260
- if (pending.state === "waiting_for_approval" && pending.approvalId) {
261
- const resumed = await run(harness, {
262
- threadId: pending.threadId,
263
- runId: pending.runId,
264
- approvalId: pending.approvalId,
265
- decision: "approve",
266
- });
267
-
268
- console.log(resumed.output);
269
- }
270
- ```
271
-
272
- Use `decision: "edit"` plus `editedInput` when your application exposes approval-time parameter editing.
273
-
274
- #### Always Stop The Harness
275
-
276
- Call `stop(...)` before process exit so the runtime can close adapters and flush state cleanly.
154
+ ### Subscribe To Global Events
277
155
 
278
156
  ```ts
279
- await stop(harness);
280
- ```
281
-
282
- For most applications, the safe pattern is `try/finally`.
283
-
284
- #### Complete SDK CLI Example
285
-
286
- The following example shows a small CLI-style integration that:
287
-
288
- - loads a workspace from disk
289
- - starts a first run with streaming output
290
- - continues the same thread
291
- - reads the saved thread state back
292
- - shuts the harness down cleanly
293
-
294
- ```ts
295
- import { createAgentHarness, getThread, run, stop } from "@botbotgo/agent-harness";
296
-
297
- const workspaceRoot = "/absolute/path/to/workspace";
298
- const harness = await createAgentHarness(workspaceRoot);
299
-
300
- try {
301
- const first = await run(harness, {
302
- agentId: "auto",
303
- input: "Explain what agents and tools are available in this workspace.",
304
- listeners: {
305
- onChunk(chunk) {
306
- process.stdout.write(chunk);
307
- },
308
- onStep(step) {
309
- console.log("\n[step]", step);
310
- },
311
- },
312
- });
313
-
314
- console.log("\nfirst run:", first.runId, first.state);
315
-
316
- const second = await run(harness, {
317
- agentId: "auto",
318
- threadId: first.threadId,
319
- input: "Now give me the shortest possible summary in 3 bullets.",
320
- });
321
-
322
- console.log("\nsecond run output:\n", second.output);
323
-
324
- const thread = await getThread(harness, first.threadId);
325
- console.log("\nthread message count:", thread?.messages.length ?? 0);
326
- } finally {
327
- await stop(harness);
328
- }
329
- ```
330
-
331
- For a real CLI entrypoint, wrap this in an async `main()` and feed the prompt from `process.argv`.
332
-
333
- ```ts
334
- import { createAgentHarness, getThread, run, subscribe, stop } from "@botbotgo/agent-harness";
335
-
336
- const harness = await createAgentHarness("/absolute/path/to/workspace");
157
+ import { subscribe } from "@botbotgo/agent-harness";
337
158
 
338
159
  const unsubscribe = subscribe(harness, (event) => {
339
- console.log(event.eventType, event.payload);
160
+ console.log(event.threadId, event.runId, event.eventType);
340
161
  });
341
-
342
- try {
343
- const firstRun = await run(harness, {
344
- agentId: "orchestra",
345
- input: "Inspect the workspace and explain the available agents.",
346
- listeners: {
347
- onChunk(chunk) {
348
- process.stdout.write(chunk);
349
- },
350
- },
351
- });
352
-
353
- const thread = await getThread(harness, firstRun.threadId);
354
- console.log(thread?.messages.at(-1)?.content);
355
- } finally {
356
- unsubscribe();
357
- await stop(harness);
358
- }
359
162
  ```
360
163
 
361
- ### 2. Use It Inside An App Workspace
362
-
363
- The example app in [`examples/stock-research-app`](/Users/boqiang.liang/900-project/agent-harness/examples/stock-research-app/README.md) is the reference shape for an application workspace. It keeps the framework package separate from app-specific agents, tools, and skills.
164
+ ### Stop The Harness
364
165
 
365
- Run the example:
166
+ ```ts
167
+ import { stop } from "@botbotgo/agent-harness";
366
168
 
367
- ```bash
368
- cd examples/stock-research-app
369
- npm install
370
- npm run start -- "Investigate NVDA and produce a balanced stock research brief."
169
+ await stop(harness);
371
170
  ```
372
171
 
373
172
  ## How To Configure
374
173
 
375
- Agent Harness is workspace-first. The runtime is assembled from files on disk rather than from a large constructor API.
174
+ Core workspace files:
376
175
 
377
- ### Core Files
378
-
379
- - `AGENTS.md`: durable instructions and operating rules loaded into agent memory where configured
380
- - `config/models.yaml`: declared models
381
- - `config/runtime.yaml`: workspace-wide runtime defaults such as `runRoot` and host routing
382
- - `config/agents/direct.yaml`: lightweight direct-response host agent
176
+ - `config/workspace.yaml`: workspace-wide defaults such as `runRoot`, routing, and maintenance
177
+ - `config/agent-context.md`: shared bootstrap context for agents
178
+ - `config/models.yaml`: named model presets
179
+ - `config/agents/direct.yaml`: lightweight host agent
383
180
  - `config/agents/orchestra.yaml`: default orchestration host agent
384
- - `config/embedding-model.yaml`: embeddings preset for retrieval flows
385
- - `config/vector-store.yaml`: vector store preset for retrieval flows
386
- - `resources/package.json`: resource package boundary for local tools and skills
387
- - `resources/tools/`: local code-authored tools discovered automatically
388
- - `resources/skills/`: local skills and skill-local assets
389
-
390
- ### Minimal Model Config
391
-
392
- ```yaml
393
- apiVersion: agent-harness/v1alpha1
394
- kind: Models
395
- spec:
396
- - name: default
397
- provider: ollama
398
- model: gpt-oss:latest
399
- init:
400
- baseUrl: http://localhost:11434
401
- temperature: 0.2
402
- ```
403
-
404
- ### Runtime Routing
405
-
406
- `config/runtime.yaml` controls shared runtime behavior. In this repo it defines:
407
-
408
- - `runRoot`: where thread state, run artifacts, approvals, and indexes are stored
409
- - `routing.systemPrompt`: how the harness chooses between the primary and secondary host agents when `agentId: "auto"` is used
181
+ - `resources/package.json`: resource package boundary
182
+ - `resources/tools/`: local tool modules
183
+ - `resources/skills/`: local skills
410
184
 
411
- ### Agent Config
185
+ ### `config/workspace.yaml`
412
186
 
413
- Agent objects are declarative YAML files. The package supports:
187
+ Use this file for workspace-wide behavior such as:
414
188
 
415
- - `LangChainAgent`
416
- - `DeepAgent`
189
+ - `runRoot`
190
+ - routing via `routing.systemPrompt`
191
+ - background checkpoint maintenance via `maintenance.checkpoints.*`
417
192
 
418
- Typical fields include:
193
+ ### `config/agent-context.md`
419
194
 
420
- - `metadata.name`
421
- - `metadata.description`
422
- - `spec.modelRef`
423
- - `spec.systemPrompt`
424
- - `spec.tools`
425
- - `spec.mcpServers`
426
- - `spec.checkpointer`
427
- - `spec.memory`
428
- - `spec.store`
429
- - `spec.backend`
195
+ Use this file for shared bootstrap context that agents should read at construction time.
430
196
 
431
- Use `LangChainAgent` for a fast direct path. Use `DeepAgent` when you need richer orchestration, tool-heavy execution, memory backends, and delegation.
197
+ Put stable project context here, not long-term mutable memory.
432
198
 
433
- ### Local Tool Authoring
199
+ If a runnable app workspace also includes `AGENTS.md`, treat that file as workspace-level operating guidance. It complements `config/agents/*.yaml` rather than replacing it: `AGENTS.md` carries durable behavioral rules, while `config/agents/` defines agent topology and runtime configuration.
434
200
 
435
- Local tools live under `resources/tools/` and are discovered automatically from `.js`, `.mjs`, and `.cjs` modules.
201
+ ### Agent YAML
436
202
 
437
- `resources/package.json` is not only metadata. It defines the dependency boundary for local tools and skill-local scripts. Tool modules are loaded with `resources/` as their package root, so dependencies should be declared under `resources/package.json` rather than relying on the app root package.
203
+ Use `config/agents/*.yaml` to configure agents. Common fields include:
438
204
 
439
- Recommended authoring style:
440
-
441
- ```js
442
- import { z } from "zod";
443
- import { tool } from "@botbotgo/agent-harness/tools";
444
-
445
- export const stock_lookup = tool({
446
- description: "Lookup a ticker.",
447
- schema: {
448
- ticker: z.string().min(1),
449
- },
450
- async invoke(input) {
451
- return input.ticker.toUpperCase();
452
- },
453
- });
454
- ```
455
-
456
- Then reference the tool from the agent:
457
-
458
- ```yaml
459
- spec:
460
- tools:
461
- - tool/stock_lookup
462
- ```
463
-
464
- ### MCP Servers On Agents
465
-
466
- MCP servers are configured directly on the agent. The framework connects to each server, lists its remote tools, and automatically exposes the selected ones on that agent.
467
-
468
- ```yaml
469
- spec:
470
- modelRef: model/default
471
- mcpServers:
472
- - name: chrome-devtools
473
- command: npx
474
- args:
475
- - chrome-devtools-mcp@latest
476
- toolFilter:
477
- - ^page_
478
- - ^network_
479
- excludeToolFilter:
480
- - _deprecated$
481
- ```
482
-
483
- Supported MCP fields:
484
-
485
- - `name`
486
- - `command`, `args`, `env`, `cwd`
487
- - `transport`, `url`, `token`, `headers`
205
+ - `modelRef`
206
+ - `systemPrompt`
488
207
  - `tools`
489
- - `excludeTools`
490
- - `toolFilter` or `toolFilters`
491
- - `excludeToolFilter` or `excludeToolFilters`
492
-
493
- ## How To Extend
494
-
495
- The extension model is filesystem-based. You extend the harness by adding new config objects, new discovery roots, or new resource packages.
496
-
497
- ### Add More Agents
498
-
499
- Agents live under config roots such as `config/agents/`. The discovery layer supports:
500
-
501
- - local filesystem paths
502
- - external resource sources
503
- - builtin discovery paths
208
+ - `skills`
209
+ - `memory`
210
+ - `checkpointer`
211
+ - `store`
212
+ - `backend`
213
+ - `subagents`
504
214
 
505
- The harness scans YAML files under the discovered agent roots and adds them to the workspace graph. `resources/` is for executable assets such as tools and skills, not agent YAML.
215
+ ### Resource Package
506
216
 
507
- ### Add Skills
217
+ Use `resources/` for executable extensions:
508
218
 
509
- Skills are discovered from roots that contain either:
510
-
511
- - a direct `SKILL.md`
512
- - child directories where each directory contains its own `SKILL.md`
513
-
514
- `SKILL.md` should use YAML frontmatter. The harness reads `name` and the standard `stack` field from frontmatter, then exposes that metadata through runtime inventory helpers such as `listAgentSkills(...)` and `builtin.list_available_skills`.
515
-
516
- Example:
517
-
518
- ```md
519
- ---
520
- name: code-review
521
- description: Review code changes for correctness and regression risk.
522
- stack:
523
- - typescript
524
- - vitest
525
- ---
526
-
527
- # Code Review
528
-
529
- Use this skill when the user wants a correctness-focused review of a patch.
530
- ```
531
-
532
- Notes:
533
-
534
- - `name` should be stable and unique within the discovered skill set
535
- - `stack` should be a list of technologies, frameworks, or platforms the skill is designed for
536
- - if `stack` is omitted, the runtime treats it as an empty list
537
-
538
- A practical layout looks like this:
539
-
540
- ```text
541
- your-workspace/
542
- resources/
543
- skills/
544
- code-review/
545
- SKILL.md
546
- release-check/
547
- SKILL.md
548
- ```
549
-
550
- ### Add Tools
551
-
552
- Tools can come from:
553
-
554
- - local modules under `resources/tools/`
555
- - external sources
556
- - builtin resources
557
- - MCP servers declared on an agent under `spec.mcpServers`
558
-
559
- The example application demonstrates the local pattern: keep app-specific tools under `resources/tools/` and keep one tool per module.
560
-
561
- Dependency rule:
562
-
563
- - declare tool runtime dependencies in `resources/package.json`
564
- - do not rely on the app root `package.json` for modules imported by files under `resources/tools/`
565
- - keep reusable helper modules for tools under `resources/` so they stay inside the same package boundary
566
-
567
- ### Add Retrieval
568
-
569
- If your workspace needs RAG-style behavior:
570
-
571
- 1. add an `EmbeddingModel`
572
- 2. add a `VectorStore`
573
- 3. point retrieval-oriented tools at those refs
574
-
575
- This repo already includes `config/embedding-model.yaml` and `config/vector-store.yaml` as the default pattern.
576
-
577
- ### Extend The Runtime In Code
578
-
579
- The public API also accepts a prebuilt `WorkspaceBundle`, which lets you compile or inject workspace data yourself before creating the harness. That path is useful when you need tighter control in tests or in a higher-level product.
580
-
581
- ## Suggested Workspace Layout
582
-
583
- ```text
584
- your-workspace/
585
- AGENTS.md
586
- config/
587
- models.yaml
588
- runtime.yaml
589
- agents/
590
- direct.yaml
591
- orchestra.yaml
592
- embedding-model.yaml
593
- vector-store.yaml
594
- resources/
595
- package.json
596
- skills/
597
- tools/
598
- .agent/
599
- ```
600
-
601
- ## Release Flow
602
-
603
- Publishing is automated from `master`.
604
-
605
- When a commit lands on `master`, the GitHub `Release` workflow:
606
-
607
- 1. runs `npm ci`, `npm run build`, `npm run check`, and `npm test`
608
- 2. bumps the package with `npm version patch --no-git-tag-version`
609
- 3. syncs `examples/stock-research-app/package.json` to the new package version
610
- 4. commits the version change back to `master` and creates a matching `v*` tag
611
- 5. verifies the tarball and publishes to npm
612
-
613
- That means normal feature and fix commits should not manually edit the package version. Version bumps are owned by the release workflow.
614
-
615
- ## Development
616
-
617
- Build and test this package locally:
618
-
619
- ```bash
620
- npm run build
621
- npm run check
622
- npm test
623
- ```
219
+ - `resources/tools/` for local tool modules
220
+ - `resources/skills/` for skill packages
624
221
 
625
- The example workspace under [`examples/stock-research-app`](/Users/boqiang.liang/900-project/agent-harness/examples/stock-research-app/README.md) is the fastest way to understand how an app should package its own agents, tools, and skills around this framework.
222
+ Each resource package should include its own `package.json`.