@stevenvincentone/intidev-agentloops 0.1.0
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/CHANGELOG.md +31 -0
- package/LICENSE +21 -0
- package/README.md +221 -0
- package/agentloop.config.json.example +31 -0
- package/dist/aliases.d.ts +25 -0
- package/dist/aliases.js +42 -0
- package/dist/backend.d.ts +29 -0
- package/dist/backend.js +40 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +497 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +81 -0
- package/dist/convergence.d.ts +56 -0
- package/dist/convergence.js +64 -0
- package/dist/dashboard.d.ts +23 -0
- package/dist/dashboard.js +234 -0
- package/dist/guards.d.ts +53 -0
- package/dist/guards.js +87 -0
- package/dist/handoff.d.ts +10 -0
- package/dist/handoff.js +23 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +80 -0
- package/dist/knowledge.d.ts +101 -0
- package/dist/knowledge.js +155 -0
- package/dist/mcp.d.ts +130 -0
- package/dist/mcp.js +442 -0
- package/dist/postgres.d.ts +104 -0
- package/dist/postgres.js +364 -0
- package/dist/prior-art.d.ts +65 -0
- package/dist/prior-art.js +114 -0
- package/dist/redaction.d.ts +14 -0
- package/dist/redaction.js +57 -0
- package/dist/serve.d.ts +8 -0
- package/dist/serve.js +42 -0
- package/dist/storage.d.ts +22 -0
- package/dist/storage.js +39 -0
- package/dist/store.d.ts +60 -0
- package/dist/store.js +339 -0
- package/dist/types.d.ts +156 -0
- package/dist/types.js +3 -0
- package/docs/architecture.md +30 -0
- package/docs/config.md +88 -0
- package/docs/mcp.md +88 -0
- package/docs/postgres.md +84 -0
- package/package.json +88 -0
package/docs/config.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
`agentloop.config.json` controls the project vocabulary.
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"projectName": "IntiDev AgentLoops",
|
|
8
|
+
"description": "Feedback loops for agentic workflows",
|
|
9
|
+
"defaultKind": "bug",
|
|
10
|
+
"ticketKinds": [
|
|
11
|
+
{ "kind": "bug", "defaultSeverity": "high", "requiredFields": ["summary"] },
|
|
12
|
+
{ "kind": "feature", "defaultSeverity": "medium", "requiredFields": ["summary"] }
|
|
13
|
+
],
|
|
14
|
+
"queues": [
|
|
15
|
+
{ "prefix": "USER", "kinds": ["user_feedback"], "sources": ["user_report"] },
|
|
16
|
+
{ "prefix": "DEV", "kinds": ["feature", "task", "investigation", "tech_debt"] },
|
|
17
|
+
{ "prefix": "ISSUE", "kinds": ["bug", "incident"], "default": true }
|
|
18
|
+
],
|
|
19
|
+
"sources": ["user_report", "manual_admin", "agent", "smoke", "ci", "ingestion"]
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Ticket kinds
|
|
24
|
+
|
|
25
|
+
Each kind can define:
|
|
26
|
+
|
|
27
|
+
- `defaultSeverity`: used when `--severity` is omitted
|
|
28
|
+
- `requiredFields`: enforcement when creating tickets
|
|
29
|
+
|
|
30
|
+
### Queues and aliases
|
|
31
|
+
|
|
32
|
+
Canonical ids are always stored as `ISSUE-000123`. Each ticket also gets one
|
|
33
|
+
user-facing **queue alias** derived from its `kind` and `source`:
|
|
34
|
+
|
|
35
|
+
- `queues` are evaluated in order; the first whose `sources` includes the
|
|
36
|
+
ticket's source, or whose `kinds` includes its kind, wins.
|
|
37
|
+
- a `sources` match takes that queue's precedence, so a `user_report`-sourced
|
|
38
|
+
bug routes to `USER-000123` even though `bug` is otherwise an `ISSUE` kind.
|
|
39
|
+
- the queue marked `"default": true` is the fallback when nothing matches.
|
|
40
|
+
|
|
41
|
+
With the default config that yields:
|
|
42
|
+
|
|
43
|
+
- `USER-000123` for product/support feedback (kind `user_feedback` or source `user_report`)
|
|
44
|
+
- `DEV-000123` for development work (`feature`, `task`, `investigation`, `tech_debt`)
|
|
45
|
+
- `ISSUE-000123` for defects (`bug`, `incident`) and anything unrouted
|
|
46
|
+
|
|
47
|
+
The canonical `ISSUE-` key keeps downstream systems stable while the alias gives
|
|
48
|
+
each operational queue a recognizable prefix. Aliases and canonical ids share the
|
|
49
|
+
same number, and any of them resolves back to the same ticket on lookup.
|
|
50
|
+
|
|
51
|
+
### Prior-art scoring (optional)
|
|
52
|
+
|
|
53
|
+
`agentloop related <id>` (and the `agentloop_related` MCP tool) rank related
|
|
54
|
+
tickets from deterministic signals: shared family, shared pattern, shared tags,
|
|
55
|
+
same kind, and title/summary token overlap. Core ships fixed default weights; a
|
|
56
|
+
project can override any of them, or raise the default match threshold:
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"priorArt": {
|
|
61
|
+
"weights": { "family": 3, "pattern": 3, "tag": 2, "kind": 1, "textOverlap": 4 },
|
|
62
|
+
"minScore": 1
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Omit `priorArt` entirely to use the core defaults.
|
|
68
|
+
|
|
69
|
+
### Redaction (optional)
|
|
70
|
+
|
|
71
|
+
By default ticket text is stored unchanged. Add regex rules under
|
|
72
|
+
`redaction.patterns` to scrub sensitive content (PII, secrets) on every write —
|
|
73
|
+
titles, summaries, notes, resolutions, and guard summaries, via both the CLI and
|
|
74
|
+
the MCP write tools:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"redaction": {
|
|
79
|
+
"patterns": [
|
|
80
|
+
{ "name": "email", "pattern": "[\\w.]+@[\\w.]+\\.[a-z]+", "replacement": "[email]" }
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Each rule takes a `pattern` (regex source), optional `flags` (default `g`), and
|
|
87
|
+
optional `replacement` (default `[redacted]`). Library users can instead inject a
|
|
88
|
+
`TicketRedactor` directly: `new AgentLoopStore(cwd, config, { redactor })`.
|
package/docs/mcp.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# MCP server
|
|
2
|
+
|
|
3
|
+
AgentLoops exposes a [Model Context Protocol](https://modelcontextprotocol.io)
|
|
4
|
+
server so coding agents can use the ticket ledger directly. Writes are **opt-in**:
|
|
5
|
+
the server is read-only by default and only registers the write tools (create /
|
|
6
|
+
note / workflow / resolve / guard) when started with `--write`.
|
|
7
|
+
|
|
8
|
+
## Running
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
agentloop mcp # read-only
|
|
12
|
+
agentloop mcp --write # also expose the write tools (alias: --allow-writes)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- Communicates over **stdio** using JSON-RPC. `stdout` carries only the protocol
|
|
16
|
+
stream; human-readable status (including the read-only/read-write mode) is
|
|
17
|
+
written to `stderr`.
|
|
18
|
+
- Reads/writes `.agentloops/state.json` from the **current working directory**, so
|
|
19
|
+
start it from the project root where you ran `agentloop init`.
|
|
20
|
+
- Implemented over the same `AgentLoopStore` as the CLI, so the CLI and MCP
|
|
21
|
+
surfaces always agree.
|
|
22
|
+
|
|
23
|
+
## Read-only tools
|
|
24
|
+
|
|
25
|
+
Always available; annotated `readOnlyHint: true`.
|
|
26
|
+
|
|
27
|
+
| Tool | Input | Returns |
|
|
28
|
+
| --- | --- | --- |
|
|
29
|
+
| `agentloop_summary` | none | `{ schemaVersion, generatedAt, summary }` — ticket/pattern counts |
|
|
30
|
+
| `agentloop_list` | `status?`, `kind?` | `{ ..., filters, count, tickets }` |
|
|
31
|
+
| `agentloop_show` | `id` | `{ ..., kind: "ticket", ticket }` or `{ ..., kind: "pattern", pattern }` |
|
|
32
|
+
| `agentloop_handoff` | `id` | `{ ..., ticketId, aliases, prompt }` |
|
|
33
|
+
| `agentloop_convergence` | `family?`, `minSources?`, `includeAll?` | `{ ..., filters, summary, patterns }` — patterns whose tickets span ≥ `minSources` (default 2) distinct sources |
|
|
34
|
+
| `agentloop_guard_gaps` | `family?`, `includeWaived?`, `allKinds?` | `{ ..., filters, summary, gaps }` — resolved tickets (ISSUE/USER queues by default) lacking an active regression guard |
|
|
35
|
+
| `agentloop_search_knowledge` | `family?`, `kind?`, `source?`, `tag?`, `query?`, `limit?` | `{ ..., filters, summary, entries }` — how prior resolved tickets were fixed (searchable corpus) |
|
|
36
|
+
| `agentloop_knowledge_gaps` | `family?`, `severity?`, `source?` | `{ ..., filters, summary, gaps }` — resolved tickets whose knowledge is incomplete (missing resolution or verification) |
|
|
37
|
+
| `agentloop_related` | `id`, `minScore?`, `limit?` | `{ ..., ticket, weights, related }` — prior-art lookup ranking tickets by shared family/pattern/tags/kind and title overlap (weights tunable via `config.priorArt`) |
|
|
38
|
+
|
|
39
|
+
## Write tools
|
|
40
|
+
|
|
41
|
+
Only registered with `--write`. Each returns `{ schemaVersion, generatedAt,
|
|
42
|
+
action, ticket }`, where `ticket` carries the canonical `id` and queue `aliases`.
|
|
43
|
+
|
|
44
|
+
| Tool | Input | Notes |
|
|
45
|
+
| --- | --- | --- |
|
|
46
|
+
| `agentloop_create` | `summary` (required), `title?`, `family?`, `kind?`, `source?`, `severity?`, `confidence?`, `tags?`, `handoff?` | `kind`/`family` default from config; `source` defaults to `agent` |
|
|
47
|
+
| `agentloop_note` | `id`, `body` (required), `type?`, `author?` | `type` defaults to `triage`, `author` to `agent` |
|
|
48
|
+
| `agentloop_workflow` | `id`, `status` (`active` \| `reopened` \| `deferred`), `reason?` | resolve via `agentloop_resolve`, not here |
|
|
49
|
+
| `agentloop_resolve` | `id`, `summary` (required), `verification?`, `guardStatus?`, `guardSummary?` | |
|
|
50
|
+
| `agentloop_guard` | `id`, `guardStatus`, `guardSummary?` | |
|
|
51
|
+
|
|
52
|
+
Notes:
|
|
53
|
+
|
|
54
|
+
- `id` accepts the canonical `ISSUE-NNNNNN` id, any queue alias (`DEV-...`,
|
|
55
|
+
`USER-...`, etc.), or a `PATTERN-NNNNNN` id for `agentloop_show`.
|
|
56
|
+
- `status` (for `agentloop_list`) accepts `triaged | active | resolved | reopened | deferred | all`.
|
|
57
|
+
- `kind`, `severity`, `confidence`, `guardStatus`, and note `type` are validated
|
|
58
|
+
against the configured/known values; invalid inputs return a readable error.
|
|
59
|
+
- Every envelope includes `schemaVersion` (currently `1`) and `generatedAt`.
|
|
60
|
+
Fields are added, not removed, within a schema version.
|
|
61
|
+
- Unknown ids return a tool error (`isError: true`) with a readable message
|
|
62
|
+
rather than failing the protocol call.
|
|
63
|
+
- Writes pass through the configured redactor before storage (no-op by default;
|
|
64
|
+
see `redaction.patterns` in [config](config.md) or inject a `TicketRedactor`).
|
|
65
|
+
|
|
66
|
+
## Client configuration
|
|
67
|
+
|
|
68
|
+
Claude Code:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
claude mcp add agentloop -- agentloop mcp
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Generic MCP client config:
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"agentloop": {
|
|
80
|
+
"command": "agentloop",
|
|
81
|
+
"args": ["mcp"]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If you have not installed the package globally, point the client at the built CLI
|
|
88
|
+
instead, e.g. `"command": "node", "args": ["/path/to/dist/cli.js", "mcp"]`.
|
package/docs/postgres.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Storage backends (filesystem & Postgres)
|
|
2
|
+
|
|
3
|
+
`AgentLoopStore` holds the whole ledger in memory and delegates persistence to a
|
|
4
|
+
`StateBackend`, so the same domain logic (tickets, patterns, audits, prior art)
|
|
5
|
+
runs over different stores:
|
|
6
|
+
|
|
7
|
+
| Backend | Use |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| `FilesystemStateBackend` (default) | JSON at `<cwd>/.agentloops/state.json` |
|
|
10
|
+
| `MemoryStateBackend` | ephemeral; tests and short-lived processes |
|
|
11
|
+
| `PostgresStateBackend` | a relational `ticket_*` schema in Postgres |
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { AgentLoopStore, MemoryStateBackend } from "@stevenvincentone/intidev-agentloops";
|
|
15
|
+
|
|
16
|
+
const store = new AgentLoopStore(process.cwd(), config, { backend: new MemoryStateBackend() });
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Postgres
|
|
20
|
+
|
|
21
|
+
`PostgresStateBackend` brings **no `pg` dependency** — you inject a client that
|
|
22
|
+
matches `pg.Pool`/`pg.Client` (`{ query(text, params) => Promise<{ rows }> }`).
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { Pool } from "pg";
|
|
26
|
+
import { AgentLoopStore, PostgresStateBackend } from "@stevenvincentone/intidev-agentloops";
|
|
27
|
+
|
|
28
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
29
|
+
const backend = new PostgresStateBackend(pool);
|
|
30
|
+
await backend.migrate(); // optional; load()/save() also create the schema on first use
|
|
31
|
+
|
|
32
|
+
const store = new AgentLoopStore("", config, { backend });
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- Saves are **transactional** (whole-snapshot replace), so a failed write never
|
|
36
|
+
leaves a partially-updated ledger. A `pg.Pool` is used via a single dedicated
|
|
37
|
+
connection per operation.
|
|
38
|
+
- Schema is created with `CREATE TABLE IF NOT EXISTS`, so `migrate()` is safe to
|
|
39
|
+
run repeatedly.
|
|
40
|
+
|
|
41
|
+
## CLI and MCP on Postgres
|
|
42
|
+
|
|
43
|
+
The `agentloop` CLI and `agentloop mcp` server run on Postgres automatically when
|
|
44
|
+
a connection string is configured — no flags needed:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export DATABASE_URL=postgres://user:pass@host:5432/db
|
|
48
|
+
agentloop init # creates the ticket_* schema and an empty ledger
|
|
49
|
+
agentloop create --kind bug --summary "..." --source smoke
|
|
50
|
+
agentloop summary
|
|
51
|
+
agentloop mcp # MCP server backed by Postgres
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- Connection string precedence: explicit > `DATABASE_URL` env > `config.storage.databaseUrl`.
|
|
55
|
+
Prefer the env var so secrets stay out of committed config.
|
|
56
|
+
- `pg` is an **optional peer dependency** — install it in your project (`npm install pg`)
|
|
57
|
+
when you want the Postgres backend. Filesystem users need nothing extra; if a
|
|
58
|
+
Postgres URL is set but `pg` is missing, the CLI prints an actionable error.
|
|
59
|
+
- One-shot commands open and **close** the pool so the process exits cleanly; the
|
|
60
|
+
MCP server holds the pool open until its stdin closes.
|
|
61
|
+
|
|
62
|
+
### Public schema
|
|
63
|
+
|
|
64
|
+
The canonical relational schema is exported as `TICKET_SCHEMA_SQL`:
|
|
65
|
+
|
|
66
|
+
- `loop_meta` — single row of top-level ledger state (project, sequences)
|
|
67
|
+
- `ticket_patterns`, `ticket_pattern_links` — patterns and their members
|
|
68
|
+
- `tickets`, `ticket_aliases`, `ticket_tags`, `ticket_notes`
|
|
69
|
+
|
|
70
|
+
Timestamps are stored as ISO text to keep round-trips identical to the JSON
|
|
71
|
+
backend. `serializeState` / `deserializeRows` are exported pure mappers between
|
|
72
|
+
`LoopState` and these rows.
|
|
73
|
+
|
|
74
|
+
### Running the Postgres tests
|
|
75
|
+
|
|
76
|
+
The Postgres integration test is skipped unless `DATABASE_URL` is set:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
docker run -d --name agentloops-pg -e POSTGRES_PASSWORD=postgres \
|
|
80
|
+
-e POSTGRES_DB=agentloops -p 55432:5432 postgres:16
|
|
81
|
+
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:55432/agentloops npm test
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
CI runs it automatically against a `postgres:16` service container.
|
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stevenvincentone/intidev-agentloops",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "IntiDev AgentLoops - Feedback Loops for Agentic Workflows",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./package.json": "./package.json"
|
|
15
|
+
},
|
|
16
|
+
"bin": {
|
|
17
|
+
"agentloop": "dist/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc",
|
|
21
|
+
"cli": "tsx src/cli.ts",
|
|
22
|
+
"demo": "tsx scripts/demo-seed.ts",
|
|
23
|
+
"test": "tsx --test test/*.test.ts",
|
|
24
|
+
"start": "npm run cli --",
|
|
25
|
+
"prepare": "npm run build",
|
|
26
|
+
"prepublishOnly": "npm run typecheck && npm run build && npm test",
|
|
27
|
+
"format": "npx prettier --write \"src/**/*.ts\" \"docs/**/*.md\" \"*.md\"",
|
|
28
|
+
"lint": "npx tsc --noEmit",
|
|
29
|
+
"typecheck": "npx tsc -p tsconfig.tooling.json"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"agentic",
|
|
33
|
+
"issue-tracking",
|
|
34
|
+
"ticketing",
|
|
35
|
+
"feedback-loop",
|
|
36
|
+
"devtool",
|
|
37
|
+
"observability",
|
|
38
|
+
"knowledge-base",
|
|
39
|
+
"guardrails",
|
|
40
|
+
"agent-tools"
|
|
41
|
+
],
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/StevenVincentOne/IntiDev-AgentLoops.git"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/StevenVincentOne/IntiDev-AgentLoops#readme",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/StevenVincentOne/IntiDev-AgentLoops/issues"
|
|
49
|
+
},
|
|
50
|
+
"author": {
|
|
51
|
+
"name": "Inti / Steven Vincent"
|
|
52
|
+
},
|
|
53
|
+
"engines": {
|
|
54
|
+
"node": ">=20"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/node": "^22.7.4",
|
|
61
|
+
"@types/pg": "^8.11.10",
|
|
62
|
+
"pg": "^8.13.1",
|
|
63
|
+
"prettier": "^3.3.3",
|
|
64
|
+
"tsx": "^4.19.1",
|
|
65
|
+
"typescript": "^5.6.3"
|
|
66
|
+
},
|
|
67
|
+
"files": [
|
|
68
|
+
"dist/**/*.js",
|
|
69
|
+
"dist/**/*.d.ts",
|
|
70
|
+
"README.md",
|
|
71
|
+
"LICENSE",
|
|
72
|
+
"CHANGELOG.md",
|
|
73
|
+
"docs/*.md",
|
|
74
|
+
"agentloop.config.json.example"
|
|
75
|
+
],
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
78
|
+
"zod": "^4.4.3"
|
|
79
|
+
},
|
|
80
|
+
"peerDependencies": {
|
|
81
|
+
"pg": "^8.0.0"
|
|
82
|
+
},
|
|
83
|
+
"peerDependenciesMeta": {
|
|
84
|
+
"pg": {
|
|
85
|
+
"optional": true
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|