Skip to main content
ClaudeWave
Skill82.2k repo starsupdated 2d ago

agent-work

Agent Work registry (works / work_versions): how agent outputs — github/linear entities, files, documents, tasks — get registered, deduped, and rendered as cards, and how to extend it with a new skill provider, a new shell CLI scanner, or a new Work type.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/lobehub/lobehub /tmp/agent-work && cp -r /tmp/agent-work/.agents/skills/agent-work ~/.claude/skills/agent-work
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Agent Works

A **Work** is a durable record of something an agent produced or touched — a GitHub PR/issue, a Linear issue, an entity file (pptx/xlsx/docx/pdf), a document, a task. Works render as cards under the assistant message that produced them and accumulate **versions** across operations, so the same PR edited twice shows one card with history.

Two tables (`packages/database/src/schemas/work.ts`):

- `works` — one row per resource. Identity/dedup key: `(resourceType, resourceId)` within the user/workspace scope. `currentVersionId` soft-references the latest version.
- `work_versions` — one row per registration event. Dedup: unique `(workId, toolCallId)`, so a retried registration with the same real tool call id is a no-op. Versions carry provenance (source message, producing tool) and operation-level `cumulativeCost` / `cumulativeUsage`.

## Type registry

`packages/database/src/models/work/registry.ts` is the single registry of Work types (`document` / `external` / `file` / `task`): `WORK_TYPE_ADAPTERS` is `satisfies Record<WorkType, WorkTypeAdapter>`, so a type added to `@lobechat/types` without an adapter is a compile error.

**Read-path compatibility gate**: `OPT_IN_WORK_TYPES` (currently `{'file'}`) hides newer types from clients that did not opt in (`includeFileWorks`). Released Electron clients lag by weeks and crash on unknown type descriptors (`descriptor.getIcon` on `undefined`), so a request without the opt-in receives exactly the pre-`file` set. Any NEW Work type must ship behind the same kind of opt-in.

## Registration write paths

Four write paths, two timing classes:

| Path                                                                    | When                                | Where                                                                                                                                                               |
| ----------------------------------------------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Skill structured tools + sandbox `runCommand` (github / linear)         | at tool execution                   | `WorkModel.handleSkillToolResult`, called from server `toolExecution` and the client executor (`registerClientWorkFromIntent.ts` on the legacy non-gateway runtime) |
| Shell Work scan (hetero codex/claude-code + device `lobe-local-system`) | at operation completion             | `apps/server/src/services/workRegistration/shellWorkRegistration.ts` via `registerWorksForOperation`                                                                |
| File Work scan (sandbox entity files)                                   | at operation completion             | `apps/server/src/services/workRegistration/registerWorksForOperation.ts`                                                                                            |
| Task / document works                                                   | at creation by their owning feature | `WorkModel.registerTask` / `registerDocument`                                                                                                                       |

### Execution-time: skill providers

`SKILL_TOOL_RESULT_NORMALIZERS` in `packages/database/src/models/work/index.ts` maps `WorkSkillProvider` (`github`, `linear`; vocabulary in `packages/types/src/work.ts`) to a normalizer. Both `satisfies` a `Record<WorkSkillProvider, …>`, so provider list and normalizer map cannot drift.

A normalizer turns one tool result into `ExternalToolWorkOperation | null` — null means "not Work-worthy", which is the common case and never an error.

### Completion-time: the shell Work scan framework

Heterogeneous CLI agents (codex, claude-code) and the device `lobe-local-system` tool run CLIs like `gh` through their own shell surfaces, which never pass the skill-tool hook. `registerWorksForOperation` recovers their Works at completion from the persisted command text + stdout. Layering:

```
registerWorksForOperation (registerWorksForOperation.ts)
  ├─ collectOperationRecords         one pass over the operation tree, shared by both scans
  ├─ registerShellWorks              (shellWorkRegistration.ts — the ENGINE, command-agnostic)
  │    ├─ SHELL_COMMAND_SOURCES      identifier→apiName scoping of shell surfaces
  │    ├─ success gate               plugin error / state.success===false / state.error → skip
  │    ├─ extract {command, exitCode, output}   from arguments / state / message content
  │    └─ shellWorkScanners/         one file per CLI family
  │         ├─ types.ts              ShellWorkScanner = { matches, name, register }
  │         ├─ github.ts             matches: includes('gh ') → workModel.registerShellGithubResult
  │         └─ index.ts              SHELL_WORK_SCANNERS registry
  └─ file Work scan                  aggregate per-path fold + sandbox export pipeline (NOT a scanner)
```

Command parsing is split the same way: `packages/database/src/models/work/shellCommandParsing.ts` holds the command-agnostic layer (POSIX-ish tokenizer, control-operator segmenting, codex `/bin/zsh -lc` wrapper expansion — `parseShellCommandSegments`), while `githubToolResult.ts` holds only the gh-specific `parseGhSegment` + field mapping.

### Cost granularity: execution-time vs completion-time

`cumulativeCost` / `cumulativeUsage` are per-version SNAPSHOTS ("spend up to this version"), never deltas — summing them across versions double-counts on every path.

- **Execution-time registrations** (skill providers) snapshot right after `UsageCounter.accumulateTool` for that call, so create + edit + edit within one run carries an INCREASING series (e.g. $0.30 → $0.70 → $1.20) and step deltas are recoverable.
- **Completion-time registrations** (shell scan, file scan) attach one OPERATION-LEVEL figure — the completing run's terminal
add-provider-docSkill

Add documentation for a new AI provider — usage docs, env vars, Docker config, image resources.

add-setting-envSkill

Add server-side environment variables that control default values for user settings.

agent-runtime-hooksSkill

Agent runtime lifecycle hooks. Use for before/after tool or step hooks, tool mocks, human intervention, sub-agent calls, context compression, evals, callAgent, or lifecycle events.

agent-signalSkill

Build or extend LobeHub Agent Signal pipelines. Use for signal sources, signal/action types, policies, middleware, workflow handoff, dedupe, scope behavior, or observability.

agent-tracingSkill

Agent tracing CLI for execution snapshots. Use for agent-tracing, traces, snapshots, LLM call inspection, context engine data, agent step analysis, execution debugging, or pulling remote/production traces ("拉线上 tracing") by operation id. Also the first stop for debugging agent tool calls — wrong or missing tool_calls, unexpected tool arguments or results, which tools were available at a step, or why a tool ran where it did.

builtin-toolSkill

Build LobeHub builtin tool packages. Use when adding agent-callable tools, manifests, executors, runtimes, inspectors, renders, placeholders, streaming, interventions, portals, or tool registries.

chat-sdkSkill

Build multi-platform chat bots with the chat SDK. Use for Slack, Teams, Google Chat, Discord, GitHub, Linear bots, webhooks, mentions, slash commands, cards, modals, or streaming responses.

cli-backend-testingSkill

>