clawck 0.4.3 → 0.5.2
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 +81 -9
- package/dist/cli/index.js +29 -44
- package/dist/cli/index.js.map +1 -1
- package/dist/core/atp.d.ts +1 -1
- package/dist/core/atp.d.ts.map +1 -1
- package/dist/core/atp.js +1 -1
- package/dist/core/atp.js.map +1 -1
- package/dist/core/clawck.d.ts.map +1 -1
- package/dist/core/clawck.js +14 -0
- package/dist/core/clawck.js.map +1 -1
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +58 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/database.d.ts +13 -0
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +151 -65
- package/dist/core/database.js.map +1 -1
- package/dist/core/errors.d.ts +19 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +40 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/logger.d.ts +14 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +39 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/pricing.d.ts +28 -0
- package/dist/core/pricing.d.ts.map +1 -0
- package/dist/core/pricing.js +48 -0
- package/dist/core/pricing.js.map +1 -0
- package/dist/core/runtime.d.ts +9 -0
- package/dist/core/runtime.d.ts.map +1 -1
- package/dist/core/runtime.js +33 -0
- package/dist/core/runtime.js.map +1 -1
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/core/sync.js +3 -0
- package/dist/core/sync.js.map +1 -1
- package/dist/core/types.d.ts +14 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/webhooks.d.ts.map +1 -1
- package/dist/core/webhooks.js +5 -2
- package/dist/core/webhooks.js.map +1 -1
- package/dist/dashboard/index.js +3 -3
- package/dist/hooks/adapters.d.ts.map +1 -1
- package/dist/hooks/adapters.js +3 -2
- package/dist/hooks/adapters.js.map +1 -1
- package/dist/hooks/handler.d.ts.map +1 -1
- package/dist/hooks/handler.js +7 -5
- package/dist/hooks/handler.js.map +1 -1
- package/dist/hooks/types.d.ts +1 -0
- package/dist/hooks/types.d.ts.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/reports/html.d.ts +2 -2
- package/dist/reports/html.d.ts.map +1 -1
- package/dist/reports/html.js +238 -84
- package/dist/reports/html.js.map +1 -1
- package/dist/reports/pdf.d.ts.map +1 -1
- package/dist/reports/pdf.js +5 -4
- package/dist/reports/pdf.js.map +1 -1
- package/dist/server/api.d.ts.map +1 -1
- package/dist/server/api.js +57 -18
- package/dist/server/api.js.map +1 -1
- package/dist/server/mcp.d.ts.map +1 -1
- package/dist/server/mcp.js +3 -3
- package/dist/server/mcp.js.map +1 -1
- package/docs/api-reference.md +380 -0
- package/docs/deployment.md +140 -0
- package/docs/deprecation-policy.md +32 -0
- package/docs/migration-guide.md +78 -0
- package/docs/security.md +70 -0
- package/docs/versioning.md +49 -0
- package/package.json +6 -3
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
- **Base URL:** `http://localhost:3456` (default port, configurable via `--port` or `PORT` env var)
|
|
6
|
+
- **Content-Type:** `application/json` for all request/response bodies
|
|
7
|
+
- **Error format:** `{ "error": "description" }` with appropriate HTTP status code
|
|
8
|
+
- **No API versioning prefix** — endpoints are at `/api/*` directly
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Health
|
|
13
|
+
|
|
14
|
+
### GET /api/health
|
|
15
|
+
|
|
16
|
+
Health check.
|
|
17
|
+
|
|
18
|
+
**Response:** `200 OK`
|
|
19
|
+
```json
|
|
20
|
+
{ "status": "ok", "version": "0.4.3", "spec": "0.2.0" }
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### GET /api/stats
|
|
24
|
+
|
|
25
|
+
Quick database statistics.
|
|
26
|
+
|
|
27
|
+
**Response:** `200 OK`
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"total_entries": 150,
|
|
31
|
+
"running": 2,
|
|
32
|
+
"clients": 5,
|
|
33
|
+
"projects": 12,
|
|
34
|
+
"agents": 3
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Time Tracking
|
|
41
|
+
|
|
42
|
+
### POST /api/start
|
|
43
|
+
|
|
44
|
+
Start tracking a task. Returns the created entry with a generated UUID.
|
|
45
|
+
|
|
46
|
+
**Request body:**
|
|
47
|
+
| Field | Type | Required | Description |
|
|
48
|
+
|-------|------|----------|-------------|
|
|
49
|
+
| task | string | yes | Task description |
|
|
50
|
+
| project | string | no | Project name |
|
|
51
|
+
| client | string | no | Client name |
|
|
52
|
+
| category | string | no | One of: `research`, `content`, `code`, `data_entry`, `design`, `communication`, `analysis`, `testing`, `planning`, `other` |
|
|
53
|
+
| agent | string | no | Agent identifier |
|
|
54
|
+
| model | string | no | LLM model name |
|
|
55
|
+
| tags | string[] | no | Arbitrary tags |
|
|
56
|
+
|
|
57
|
+
**Response:** `201 Created` — full `ClawckEntry` object
|
|
58
|
+
|
|
59
|
+
### POST /api/stop
|
|
60
|
+
|
|
61
|
+
Stop a running task.
|
|
62
|
+
|
|
63
|
+
**Request body:**
|
|
64
|
+
| Field | Type | Required | Description |
|
|
65
|
+
|-------|------|----------|-------------|
|
|
66
|
+
| id | string | yes | Entry ID |
|
|
67
|
+
| status | string | no | `completed` or `failed` (default: `completed`) |
|
|
68
|
+
| summary | string | no | Summary of work done |
|
|
69
|
+
| tokens_in | number | no | Input tokens consumed |
|
|
70
|
+
| tokens_out | number | no | Output tokens generated |
|
|
71
|
+
| cost_usd | number | no | Estimated cost in USD |
|
|
72
|
+
| tool_calls | number | no | Number of tool calls made |
|
|
73
|
+
|
|
74
|
+
**Response:** `200 OK` — updated `ClawckEntry` object
|
|
75
|
+
**Error:** `404` if entry not found
|
|
76
|
+
|
|
77
|
+
### POST /api/log
|
|
78
|
+
|
|
79
|
+
Log a completed task retroactively (task already finished, recording it after the fact).
|
|
80
|
+
|
|
81
|
+
**Request body:**
|
|
82
|
+
| Field | Type | Required | Description |
|
|
83
|
+
|-------|------|----------|-------------|
|
|
84
|
+
| task | string | yes | Task description |
|
|
85
|
+
| duration_minutes | number | yes | How long the task took |
|
|
86
|
+
| project | string | no | Project name |
|
|
87
|
+
| client | string | no | Client name |
|
|
88
|
+
| category | string | no | Task category |
|
|
89
|
+
| agent | string | no | Agent identifier |
|
|
90
|
+
| model | string | no | LLM model name |
|
|
91
|
+
| summary | string | no | Summary of work done |
|
|
92
|
+
| tokens_in | number | no | Input tokens consumed |
|
|
93
|
+
| tokens_out | number | no | Output tokens generated |
|
|
94
|
+
| cost_usd | number | no | Estimated cost |
|
|
95
|
+
| tags | string[] | no | Tags |
|
|
96
|
+
|
|
97
|
+
**Response:** `201 Created` — full `ClawckEntry` object
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Entries
|
|
102
|
+
|
|
103
|
+
### GET /api/entries
|
|
104
|
+
|
|
105
|
+
Query entries with filters.
|
|
106
|
+
|
|
107
|
+
**Query parameters:**
|
|
108
|
+
| Param | Type | Description |
|
|
109
|
+
|-------|------|-------------|
|
|
110
|
+
| client | string | Filter by client |
|
|
111
|
+
| project | string | Filter by project |
|
|
112
|
+
| agent | string | Filter by agent |
|
|
113
|
+
| category | string | Filter by category |
|
|
114
|
+
| status | string | Filter by status (`running`, `completed`, `failed`, `paused`) |
|
|
115
|
+
| from | string | Start date (ISO 8601) |
|
|
116
|
+
| to | string | End date (ISO 8601) |
|
|
117
|
+
| limit | number | Max entries (default: 500) |
|
|
118
|
+
|
|
119
|
+
**Response:** `200 OK` — array of `ClawckEntry` objects
|
|
120
|
+
|
|
121
|
+
### GET /api/entries/:id
|
|
122
|
+
|
|
123
|
+
Get a single entry by ID.
|
|
124
|
+
|
|
125
|
+
**Response:** `200 OK` — `ClawckEntry` object
|
|
126
|
+
**Error:** `404` if not found
|
|
127
|
+
|
|
128
|
+
### PATCH /api/entries/:id
|
|
129
|
+
|
|
130
|
+
Update fields on an existing entry.
|
|
131
|
+
|
|
132
|
+
**Request body:** Any subset of entry fields (task, project, client, category, status, summary, tokens_in, tokens_out, cost_usd, tool_calls, tags, agent, approved)
|
|
133
|
+
|
|
134
|
+
**Response:** `200 OK` — updated `ClawckEntry` object
|
|
135
|
+
**Error:** `404` if not found
|
|
136
|
+
|
|
137
|
+
### POST /api/entries/:id/approve
|
|
138
|
+
|
|
139
|
+
Mark an entry as approved.
|
|
140
|
+
|
|
141
|
+
**Response:** `200 OK` — updated `ClawckEntry` object with `approved: true`
|
|
142
|
+
**Error:** `404` if not found
|
|
143
|
+
|
|
144
|
+
### GET /api/running
|
|
145
|
+
|
|
146
|
+
Get all currently running entries.
|
|
147
|
+
|
|
148
|
+
**Response:** `200 OK` — array of `ClawckEntry` objects with `status: "running"`
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Reporting
|
|
153
|
+
|
|
154
|
+
### GET /api/timesheet
|
|
155
|
+
|
|
156
|
+
Get a timesheet summary for a date range.
|
|
157
|
+
|
|
158
|
+
**Query parameters:**
|
|
159
|
+
| Param | Type | Description |
|
|
160
|
+
|-------|------|-------------|
|
|
161
|
+
| from | string | Start date (ISO 8601, default: 7 days ago) |
|
|
162
|
+
| to | string | End date (ISO 8601, default: now) |
|
|
163
|
+
| client | string | Filter by client |
|
|
164
|
+
| project | string | Filter by project |
|
|
165
|
+
| agent | string | Filter by agent |
|
|
166
|
+
|
|
167
|
+
**Response:** `200 OK` — `TimesheetSummary` object with aggregated stats, breakdowns by client/agent/project/category, and individual rows
|
|
168
|
+
|
|
169
|
+
### POST /api/reports/generate
|
|
170
|
+
|
|
171
|
+
Generate a report (terminal JSON, HTML, or PDF).
|
|
172
|
+
|
|
173
|
+
**Request body:**
|
|
174
|
+
| Field | Type | Required | Description |
|
|
175
|
+
|-------|------|----------|-------------|
|
|
176
|
+
| period | string | no | `day`, `week`, `month`, `year`, `custom` |
|
|
177
|
+
| from | string | no | Start date (ISO 8601) |
|
|
178
|
+
| to | string | no | End date (ISO 8601) |
|
|
179
|
+
| days | number | no | Number of days back from now |
|
|
180
|
+
| style | string | no | `full`, `short`, `visual`, `text`, `table`, `calendar` (default: `full`) |
|
|
181
|
+
| format | string | no | `terminal`, `html`, `pdf` (default: `terminal`) |
|
|
182
|
+
| filters | object | no | `{ client?, project?, agent? }` |
|
|
183
|
+
| name | string | no | Report name (for saved reports) |
|
|
184
|
+
| save | boolean | no | Whether to save the report to the database |
|
|
185
|
+
|
|
186
|
+
**Response:** `200 OK`
|
|
187
|
+
- For `pdf` format without `save`: raw PDF binary with `Content-Type: application/pdf`
|
|
188
|
+
- Otherwise: `{ "content": "...", "metadata": { ... } }` (plus `"id"` if saved)
|
|
189
|
+
|
|
190
|
+
### GET /api/reports
|
|
191
|
+
|
|
192
|
+
List saved reports.
|
|
193
|
+
|
|
194
|
+
**Query parameters:**
|
|
195
|
+
| Param | Type | Description |
|
|
196
|
+
|-------|------|-------------|
|
|
197
|
+
| limit | number | Max results (default: 50) |
|
|
198
|
+
| offset | number | Pagination offset (default: 0) |
|
|
199
|
+
|
|
200
|
+
**Response:** `200 OK` — array of `StoredReport` objects (without content)
|
|
201
|
+
|
|
202
|
+
### GET /api/reports/:id
|
|
203
|
+
|
|
204
|
+
Get a saved report by ID (without content blob).
|
|
205
|
+
|
|
206
|
+
**Response:** `200 OK` — `StoredReport` object
|
|
207
|
+
**Error:** `404` if not found
|
|
208
|
+
|
|
209
|
+
### DELETE /api/reports/:id
|
|
210
|
+
|
|
211
|
+
Delete a saved report.
|
|
212
|
+
|
|
213
|
+
**Response:** `200 OK` — `{ "ok": true }`
|
|
214
|
+
**Error:** `404` if not found
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Baselines
|
|
219
|
+
|
|
220
|
+
### GET /api/baselines
|
|
221
|
+
|
|
222
|
+
List all personal baselines.
|
|
223
|
+
|
|
224
|
+
**Response:** `200 OK` — array of `PersonalBaseline` objects
|
|
225
|
+
|
|
226
|
+
### POST /api/baselines
|
|
227
|
+
|
|
228
|
+
Create a personal baseline.
|
|
229
|
+
|
|
230
|
+
**Request body:**
|
|
231
|
+
| Field | Type | Required | Description |
|
|
232
|
+
|-------|------|----------|-------------|
|
|
233
|
+
| category | string | yes | Task category |
|
|
234
|
+
| task_type | string | yes | Task type label |
|
|
235
|
+
| description | string | no | Description |
|
|
236
|
+
| my_minutes | number | yes | Your personal time for this task type |
|
|
237
|
+
|
|
238
|
+
**Response:** `201 Created` — `PersonalBaseline` object
|
|
239
|
+
|
|
240
|
+
### DELETE /api/baselines/:id
|
|
241
|
+
|
|
242
|
+
Delete a personal baseline.
|
|
243
|
+
|
|
244
|
+
**Response:** `200 OK` — `{ "ok": true }`
|
|
245
|
+
**Error:** `404` if not found
|
|
246
|
+
|
|
247
|
+
### GET /api/compare/:entryId
|
|
248
|
+
|
|
249
|
+
Compare an entry against industry and personal benchmarks.
|
|
250
|
+
|
|
251
|
+
**Response:** `200 OK` — comparison object with benchmark data
|
|
252
|
+
**Error:** `404` if entry not found
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Import/Export
|
|
257
|
+
|
|
258
|
+
### GET /api/export/atp
|
|
259
|
+
|
|
260
|
+
Export entries as an ATP (Agent Time Protocol) envelope.
|
|
261
|
+
|
|
262
|
+
**Query parameters:**
|
|
263
|
+
| Param | Type | Description |
|
|
264
|
+
|-------|------|-------------|
|
|
265
|
+
| from | string | Start date (default: 7 days ago) |
|
|
266
|
+
| to | string | End date (default: now) |
|
|
267
|
+
|
|
268
|
+
**Response:** `200 OK` — ATP JSON envelope (see `docs/atp-spec-v0.2.md`)
|
|
269
|
+
|
|
270
|
+
### POST /api/import/atp
|
|
271
|
+
|
|
272
|
+
Import entries from an ATP envelope.
|
|
273
|
+
|
|
274
|
+
**Request body:** ATP JSON envelope
|
|
275
|
+
|
|
276
|
+
**Response:** `200 OK` — `{ "ingested": 10, "total": 12 }`
|
|
277
|
+
|
|
278
|
+
### POST /api/ingest
|
|
279
|
+
|
|
280
|
+
Bulk import/merge entries. Entries are upserted by UUID — duplicates are updated, new entries are created.
|
|
281
|
+
|
|
282
|
+
**Request body:** Single `ClawckEntry` object or array of entries
|
|
283
|
+
|
|
284
|
+
**Response:** `200 OK` — `{ "ingested": 5, "total": 5 }`
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Sync
|
|
289
|
+
|
|
290
|
+
### GET /api/sync/status
|
|
291
|
+
|
|
292
|
+
Get sync status for configured remote sources.
|
|
293
|
+
|
|
294
|
+
**Response:** `200 OK`
|
|
295
|
+
```json
|
|
296
|
+
{ "enabled": true, "states": [{ "source_name": "...", "last_sync_at": "...", "last_status": "success", "entries_synced": 42 }] }
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### POST /api/sync/trigger
|
|
300
|
+
|
|
301
|
+
Manually trigger a sync from all remote sources.
|
|
302
|
+
|
|
303
|
+
**Response:** `200 OK` — `{ "states": [...] }`
|
|
304
|
+
**Error:** `400` if no remote sources configured
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Filter Options
|
|
309
|
+
|
|
310
|
+
### GET /api/clients
|
|
311
|
+
|
|
312
|
+
List distinct client names.
|
|
313
|
+
|
|
314
|
+
**Response:** `200 OK` — `["acme-corp", "internal"]`
|
|
315
|
+
|
|
316
|
+
### GET /api/projects
|
|
317
|
+
|
|
318
|
+
List distinct project names.
|
|
319
|
+
|
|
320
|
+
**Response:** `200 OK` — `["website-rebuild", "grant-research"]`
|
|
321
|
+
|
|
322
|
+
### GET /api/agents
|
|
323
|
+
|
|
324
|
+
List distinct agent identifiers.
|
|
325
|
+
|
|
326
|
+
**Response:** `200 OK` — `["claude-agent", "research-bot"]`
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## ClawckEntry Object
|
|
331
|
+
|
|
332
|
+
The core data model returned by most endpoints:
|
|
333
|
+
|
|
334
|
+
```json
|
|
335
|
+
{
|
|
336
|
+
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
337
|
+
"agent": "research-agent-01",
|
|
338
|
+
"model": "claude-sonnet-4-20250514",
|
|
339
|
+
"client": "acme-corp",
|
|
340
|
+
"project": "grant-research",
|
|
341
|
+
"task": "Research NEA grant opportunities",
|
|
342
|
+
"category": "research",
|
|
343
|
+
"start": "2026-03-08T10:00:00.000Z",
|
|
344
|
+
"end": "2026-03-08T10:05:30.000Z",
|
|
345
|
+
"status": "completed",
|
|
346
|
+
"tokens_in": 25000,
|
|
347
|
+
"tokens_out": 3500,
|
|
348
|
+
"cost_usd": 0.12,
|
|
349
|
+
"tool_calls": 8,
|
|
350
|
+
"summary": "Found 12 matching grants",
|
|
351
|
+
"tags": ["grants", "nea"],
|
|
352
|
+
"source": "mcp",
|
|
353
|
+
"spec_version": "0.2.0",
|
|
354
|
+
"created_at": "2026-03-08T10:00:00.000Z",
|
|
355
|
+
"updated_at": "2026-03-08T10:05:30.000Z",
|
|
356
|
+
"approved": false,
|
|
357
|
+
"agent_runtime_ms": 15200,
|
|
358
|
+
"wall_clock_ms": 330000
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## MCP Tools
|
|
365
|
+
|
|
366
|
+
Clawck's MCP server (started via `clawck mcp`) exposes these tools over stdio:
|
|
367
|
+
|
|
368
|
+
| Tool | Required Inputs | Description |
|
|
369
|
+
|------|----------------|-------------|
|
|
370
|
+
| `clawck_start_task` | `task` | Start tracking a task |
|
|
371
|
+
| `clawck_stop_task` | `id` | Stop a running task |
|
|
372
|
+
| `clawck_log_task` | `task`, `duration_minutes` | Log completed work retroactively |
|
|
373
|
+
| `clawck_status` | (none) | Get running entries and stats |
|
|
374
|
+
| `clawck_timesheet` | (none) | Get timesheet summary (defaults to last 7 days) |
|
|
375
|
+
| `clawck_get_entry` | `id` | Get a single entry |
|
|
376
|
+
| `clawck_query_entries` | (none) | Query entries with filters |
|
|
377
|
+
| `clawck_update_entry` | `id` | Update an existing entry |
|
|
378
|
+
| `clawck_list_metadata` | `type` | List clients, projects, or agents |
|
|
379
|
+
|
|
380
|
+
All tools return JSON with an `ok` boolean. See `src/server/mcp.ts` for full input schemas.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Deployment Guide
|
|
2
|
+
|
|
3
|
+
## Local Development
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
# Watch mode (auto-recompile on changes)
|
|
7
|
+
npm run dev
|
|
8
|
+
|
|
9
|
+
# Start the server directly via tsx
|
|
10
|
+
npm run serve
|
|
11
|
+
|
|
12
|
+
# Run tests
|
|
13
|
+
npm test
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Production Deployment
|
|
17
|
+
|
|
18
|
+
### Build and Run
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run build # Compile TypeScript to dist/
|
|
22
|
+
npm start # Run dist/cli/index.js
|
|
23
|
+
# or
|
|
24
|
+
clawck serve --port 3456
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Environment Variables
|
|
28
|
+
|
|
29
|
+
| Variable | Description | Default |
|
|
30
|
+
|----------|-------------|---------|
|
|
31
|
+
| `CLAWCK_DIR` | Path to the data directory | `.clawck` (relative to cwd) |
|
|
32
|
+
| `PORT` | Server port (can also use `--port` flag) | `3456` |
|
|
33
|
+
|
|
34
|
+
### systemd Example
|
|
35
|
+
|
|
36
|
+
```ini
|
|
37
|
+
[Unit]
|
|
38
|
+
Description=Clawck Time Tracking Server
|
|
39
|
+
After=network.target
|
|
40
|
+
|
|
41
|
+
[Service]
|
|
42
|
+
Type=simple
|
|
43
|
+
User=clawck
|
|
44
|
+
WorkingDirectory=/opt/clawck
|
|
45
|
+
Environment=CLAWCK_DIR=/opt/clawck/data
|
|
46
|
+
ExecStart=/usr/bin/node /opt/clawck/dist/cli/index.js serve --port 3456
|
|
47
|
+
Restart=on-failure
|
|
48
|
+
|
|
49
|
+
[Install]
|
|
50
|
+
WantedBy=multi-user.target
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### pm2 Example
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pm2 start dist/cli/index.js --name clawck -- serve --port 3456
|
|
57
|
+
pm2 save
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Data Directory Structure
|
|
61
|
+
|
|
62
|
+
The data directory (default `.clawck/`, override with `CLAWCK_DIR` or `-d` flag) contains:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
.clawck/
|
|
66
|
+
clawck.db # SQLite database (all entries, baselines, reports, sync state)
|
|
67
|
+
config.json # Configuration file
|
|
68
|
+
hooks/
|
|
69
|
+
sessions/ # Hook session state files (JSON, one per active session)
|
|
70
|
+
hook-errors.log # Append-only log of hook processing errors
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Database File
|
|
74
|
+
|
|
75
|
+
`clawck.db` is a standard SQLite database. It uses WAL mode (`journal_mode = WAL`), which creates two additional files during operation:
|
|
76
|
+
|
|
77
|
+
- `clawck.db-wal` — Write-Ahead Log
|
|
78
|
+
- `clawck.db-shm` — Shared memory file
|
|
79
|
+
|
|
80
|
+
These are normal and are managed automatically by SQLite. Do not delete them while the server is running.
|
|
81
|
+
|
|
82
|
+
### Database Pragmas
|
|
83
|
+
|
|
84
|
+
- **`journal_mode = WAL`** — Enables concurrent reads while writing. Multiple processes can read the database simultaneously, but only one can write at a time.
|
|
85
|
+
- **`synchronous = NORMAL`** — In WAL mode, this provides good durability without the performance cost of `FULL`. Data is safe against application crashes; a power loss during a write could lose the most recent transaction.
|
|
86
|
+
|
|
87
|
+
## Backup and Restore
|
|
88
|
+
|
|
89
|
+
### File Copy (Simplest)
|
|
90
|
+
|
|
91
|
+
Stop the server and copy the database file:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# Stop clawck first, then:
|
|
95
|
+
cp .clawck/clawck.db .clawck/clawck.db.bak
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### SQLite .backup (While Running)
|
|
99
|
+
|
|
100
|
+
If you cannot stop the server, use SQLite's built-in backup command:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
sqlite3 .clawck/clawck.db ".backup '/path/to/backup/clawck.db'"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This creates a consistent snapshot even while the database is in use.
|
|
107
|
+
|
|
108
|
+
### ATP Export (Portable)
|
|
109
|
+
|
|
110
|
+
Export entries as a JSON envelope for platform-independent backup:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Via CLI
|
|
114
|
+
clawck export --format json --days 365 > backup.json
|
|
115
|
+
|
|
116
|
+
# Via API
|
|
117
|
+
curl http://localhost:3456/api/export/atp?from=2025-01-01T00:00:00Z > backup-atp.json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Import into a new instance:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
curl -X POST http://localhost:3456/api/import/atp \
|
|
124
|
+
-H "Content-Type: application/json" \
|
|
125
|
+
-d @backup-atp.json
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Automated Backup (cron)
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# Daily backup at 2 AM
|
|
132
|
+
0 2 * * * sqlite3 /opt/clawck/data/clawck.db ".backup '/opt/clawck/backups/clawck-$(date +\%Y\%m\%d).db'"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Restore
|
|
136
|
+
|
|
137
|
+
1. Stop the server
|
|
138
|
+
2. Replace `clawck.db` with the backup file
|
|
139
|
+
3. Delete any stale `-wal` and `-shm` files
|
|
140
|
+
4. Start the server — migrations will auto-apply if the backup is from an older version
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Deprecation Policy
|
|
2
|
+
|
|
3
|
+
## During 0.x (current)
|
|
4
|
+
|
|
5
|
+
- Breaking changes may happen in **minor** versions (e.g., 0.5.0 → 0.6.0)
|
|
6
|
+
- All breaking changes are documented in [CHANGELOG.md](../CHANGELOG.md)
|
|
7
|
+
- Experimental features (labeled in README) may change without notice
|
|
8
|
+
|
|
9
|
+
## Post 1.0 (planned)
|
|
10
|
+
|
|
11
|
+
- Breaking changes require a **major** version bump
|
|
12
|
+
- Deprecated features receive at least **1 minor version** deprecation notice before removal
|
|
13
|
+
- Deprecation notices appear in:
|
|
14
|
+
- CHANGELOG.md
|
|
15
|
+
- Console warnings at runtime (via structured logger)
|
|
16
|
+
|
|
17
|
+
## Config Keys
|
|
18
|
+
|
|
19
|
+
- Deprecated config keys will log a warning for **2 minor versions** before removal
|
|
20
|
+
- The warning includes the replacement key/approach
|
|
21
|
+
|
|
22
|
+
## Experimental Features
|
|
23
|
+
|
|
24
|
+
Features labeled "Experimental" in the README:
|
|
25
|
+
- May change behavior, API shape, or be removed without a deprecation cycle
|
|
26
|
+
- Current experimental features: webhooks, multi-agent sync, pricing estimation
|
|
27
|
+
|
|
28
|
+
## Stable Surface
|
|
29
|
+
|
|
30
|
+
Features labeled "Stable" in the README:
|
|
31
|
+
- Will follow the deprecation policy above
|
|
32
|
+
- Current stable surfaces: CLI commands, REST API, MCP tools, SQLite storage, ATP export/import
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Migration Guide
|
|
2
|
+
|
|
3
|
+
## Database Schema Migrations
|
|
4
|
+
|
|
5
|
+
Clawck uses a versioned migration system to evolve the SQLite schema. Migrations run automatically on startup — no manual steps required.
|
|
6
|
+
|
|
7
|
+
### How It Works
|
|
8
|
+
|
|
9
|
+
1. A `schema_version` table stores a single integer indicating the current version.
|
|
10
|
+
2. On startup, Clawck compares the stored version against `ClawckDB.SCHEMA_VERSION`.
|
|
11
|
+
3. Any pending migrations run inside a single transaction — all-or-nothing.
|
|
12
|
+
4. Legacy databases (created before the migration system) are auto-detected: Clawck probes for columns and tables to infer the correct starting version.
|
|
13
|
+
|
|
14
|
+
### Migration Table
|
|
15
|
+
|
|
16
|
+
| Version | Added In | What It Does |
|
|
17
|
+
|---------|----------|--------------|
|
|
18
|
+
| 1 | v0.1.0 | Initial schema: `entries` table with all core columns, `sync_state` table, indexes on agent/client/project/status/start |
|
|
19
|
+
| 2 | v0.3.0 | Adds `approved` column (INTEGER, default 0) to `entries` |
|
|
20
|
+
| 3 | v0.3.0 | Adds `agent_runtime_ms` and `wall_clock_ms` columns (INTEGER, nullable) to `entries` |
|
|
21
|
+
| 4 | v0.3.0 | Creates `personal_baselines` table (id, category, task_type, description, my_minutes, timestamps) |
|
|
22
|
+
| 5 | v0.3.0 | Creates `reports` table (id, name, period, period_start, period_end, style, format, content BLOB, metadata, created_at) with index on created_at |
|
|
23
|
+
|
|
24
|
+
### Checking the Current Version
|
|
25
|
+
|
|
26
|
+
**Programmatically:**
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
const db = new ClawckDB(config);
|
|
30
|
+
console.log(db.getSchemaVersion()); // e.g., 5
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Via SQLite directly:**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
sqlite3 .clawck/clawck.db "SELECT version FROM schema_version"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Database Pragmas
|
|
40
|
+
|
|
41
|
+
Clawck sets these pragmas on every connection:
|
|
42
|
+
|
|
43
|
+
- `journal_mode = WAL` — Write-Ahead Logging for better concurrent read performance
|
|
44
|
+
- `synchronous = NORMAL` — Balances durability with write speed (safe for WAL mode)
|
|
45
|
+
|
|
46
|
+
## Upgrading Between Releases
|
|
47
|
+
|
|
48
|
+
### General Upgrade Steps
|
|
49
|
+
|
|
50
|
+
1. Stop the running Clawck server
|
|
51
|
+
2. Pull the new version (`npm update -g clawck` or `git pull && npm install`)
|
|
52
|
+
3. Build (`npm run build`)
|
|
53
|
+
4. Start the server (`clawck serve` or `npm start`)
|
|
54
|
+
|
|
55
|
+
Migrations run automatically on first startup after upgrade. No manual database changes needed.
|
|
56
|
+
|
|
57
|
+
### Version-Specific Notes
|
|
58
|
+
|
|
59
|
+
#### v0.1.0 to v0.3.0
|
|
60
|
+
|
|
61
|
+
- **4 new migrations** (2–5) will auto-apply. The `entries` table gains three new columns (`approved`, `agent_runtime_ms`, `wall_clock_ms`), and two new tables (`personal_baselines`, `reports`) are created.
|
|
62
|
+
- **Spec version changed** from 0.1.0 to 0.2.0. New entries use the updated spec. Existing entries retain their original `spec_version` value.
|
|
63
|
+
- **New config fields** available: `patterns`, `default_pattern`, `runtime_estimation`, `use_industry_benchmarks`, `personal_rate_usd`. All are optional with sensible defaults.
|
|
64
|
+
|
|
65
|
+
#### v0.3.0 to v0.4.x
|
|
66
|
+
|
|
67
|
+
- No schema changes (still version 5).
|
|
68
|
+
- Bug fixes to hook handling, CLI output, and runtime calculation.
|
|
69
|
+
- The `--verbose` flag was added to CLI commands.
|
|
70
|
+
|
|
71
|
+
### Rollback
|
|
72
|
+
|
|
73
|
+
There is no automated downgrade path. To roll back:
|
|
74
|
+
|
|
75
|
+
1. Stop Clawck
|
|
76
|
+
2. Restore the database file from a backup taken before the upgrade (see `docs/deployment.md` for backup guidance)
|
|
77
|
+
3. Install the older version of Clawck
|
|
78
|
+
4. Start the server
|
package/docs/security.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
This document describes Clawck's current security posture. Clawck is designed as a local/trusted-network tool — it does not include built-in authentication or authorization.
|
|
4
|
+
|
|
5
|
+
## Authentication
|
|
6
|
+
|
|
7
|
+
**Clawck has no built-in authentication.** The REST API and dashboard are open to anyone who can reach the server. This is by design for local development use.
|
|
8
|
+
|
|
9
|
+
If you expose Clawck beyond localhost, place it behind a reverse proxy with authentication:
|
|
10
|
+
|
|
11
|
+
```nginx
|
|
12
|
+
# nginx example
|
|
13
|
+
server {
|
|
14
|
+
listen 443 ssl;
|
|
15
|
+
server_name clawck.internal.example.com;
|
|
16
|
+
|
|
17
|
+
# Add your auth method (basic auth, OAuth proxy, etc.)
|
|
18
|
+
auth_basic "Clawck";
|
|
19
|
+
auth_basic_user_file /etc/nginx/.htpasswd;
|
|
20
|
+
|
|
21
|
+
location / {
|
|
22
|
+
proxy_pass http://127.0.0.1:3456;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## CORS
|
|
28
|
+
|
|
29
|
+
CORS is wide open by default (`cors()` with no restrictions). All origins, methods, and headers are allowed. To restrict this, you would need to modify `src/server/api.ts` and pass a configuration object to the `cors()` middleware.
|
|
30
|
+
|
|
31
|
+
## Input Handling
|
|
32
|
+
|
|
33
|
+
- **SQL injection:** All database queries use prepared statements via better-sqlite3. No string interpolation is used in SQL.
|
|
34
|
+
- **JSON validation:** Express `express.json()` middleware parses request bodies. Invalid JSON returns a 400 error.
|
|
35
|
+
- **Entry IDs:** UUIDs are generated via the `uuid` package (v4). ID prefix lookups use parameterized `LIKE` queries.
|
|
36
|
+
|
|
37
|
+
## Hook System
|
|
38
|
+
|
|
39
|
+
- **Execution context:** Platform hooks (`clawck hook start`, `clawck hook stop`) run as CLI commands in the calling process's context — they inherit the user's permissions and environment.
|
|
40
|
+
- **Session files:** Hook state is stored as JSON files in `.clawck/hooks/sessions/`. These are local to the data directory and are read/written by the CLI process.
|
|
41
|
+
- **Error logging:** Hook errors are appended to `.clawck/hooks/hook-errors.log`. This file grows without rotation — monitor its size in long-running deployments.
|
|
42
|
+
|
|
43
|
+
## MCP Server
|
|
44
|
+
|
|
45
|
+
The MCP server runs on stdio (stdin/stdout) and inherits the trust model of the parent process. It does not open network ports. The parent process (e.g., Claude Code, Cursor) controls access.
|
|
46
|
+
|
|
47
|
+
## Data Sensitivity
|
|
48
|
+
|
|
49
|
+
Time entries may contain:
|
|
50
|
+
- **Task descriptions** — can include sensitive project names, client names, or work details
|
|
51
|
+
- **Cost data** — token usage and estimated USD costs
|
|
52
|
+
- **Agent identifiers** — which models and agents are being used
|
|
53
|
+
|
|
54
|
+
The SQLite database file (`.clawck/clawck.db`) contains all of this data. Treat it with the same care as any business data.
|
|
55
|
+
|
|
56
|
+
## Webhooks
|
|
57
|
+
|
|
58
|
+
Webhook payloads are sent via HTTP POST to configured URLs. Payloads include entry details (task, client, project, cost). If webhook URLs point to external services, entry data leaves your network. Configure webhook URLs to trusted endpoints only.
|
|
59
|
+
|
|
60
|
+
## Summary
|
|
61
|
+
|
|
62
|
+
| Area | Status |
|
|
63
|
+
|------|--------|
|
|
64
|
+
| Authentication | None — use a reverse proxy if exposed |
|
|
65
|
+
| Authorization | None — all API endpoints are open |
|
|
66
|
+
| CORS | Open to all origins |
|
|
67
|
+
| SQL injection | Protected (prepared statements) |
|
|
68
|
+
| Transport encryption | None — use a reverse proxy with TLS |
|
|
69
|
+
| MCP | stdio-based, inherits parent trust |
|
|
70
|
+
| Data at rest | Unencrypted SQLite file |
|