ghost-dragon 4.2.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.
- package/.github/workflows/ci.yml +23 -0
- package/CHANGELOG.md +96 -0
- package/README.md +193 -0
- package/bootstrap.ps1 +83 -0
- package/bootstrap.sh +71 -0
- package/dist/agent/loop.d.ts +68 -0
- package/dist/agent/loop.d.ts.map +1 -0
- package/dist/agent/loop.js +135 -0
- package/dist/agent/mcp.d.ts +33 -0
- package/dist/agent/mcp.d.ts.map +1 -0
- package/dist/agent/mcp.js +107 -0
- package/dist/agent/session.d.ts +16 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +55 -0
- package/dist/agent/skills.d.ts +36 -0
- package/dist/agent/skills.d.ts.map +1 -0
- package/dist/agent/skills.js +153 -0
- package/dist/agent/stack.d.ts +21 -0
- package/dist/agent/stack.d.ts.map +1 -0
- package/dist/agent/stack.js +158 -0
- package/dist/agent/task.d.ts +21 -0
- package/dist/agent/task.d.ts.map +1 -0
- package/dist/agent/task.js +45 -0
- package/dist/agent/tools.d.ts +44 -0
- package/dist/agent/tools.d.ts.map +1 -0
- package/dist/agent/tools.js +262 -0
- package/dist/agent/trace.d.ts +34 -0
- package/dist/agent/trace.d.ts.map +1 -0
- package/dist/agent/trace.js +72 -0
- package/dist/agent.d.ts +46 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +103 -0
- package/dist/auth.d.ts +74 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +116 -0
- package/dist/brain/anthropic.d.ts +19 -0
- package/dist/brain/anthropic.d.ts.map +1 -0
- package/dist/brain/anthropic.js +74 -0
- package/dist/brain/claude-cli.d.ts +20 -0
- package/dist/brain/claude-cli.d.ts.map +1 -0
- package/dist/brain/claude-cli.js +79 -0
- package/dist/brain/ghost-ember.d.ts +28 -0
- package/dist/brain/ghost-ember.d.ts.map +1 -0
- package/dist/brain/ghost-ember.js +97 -0
- package/dist/brain/index.d.ts +22 -0
- package/dist/brain/index.d.ts.map +1 -0
- package/dist/brain/index.js +95 -0
- package/dist/brain/openai-compat.d.ts +21 -0
- package/dist/brain/openai-compat.d.ts.map +1 -0
- package/dist/brain/openai-compat.js +119 -0
- package/dist/brain/router/classify.d.ts +23 -0
- package/dist/brain/router/classify.d.ts.map +1 -0
- package/dist/brain/router/classify.js +160 -0
- package/dist/brain/router/execute.d.ts +23 -0
- package/dist/brain/router/execute.d.ts.map +1 -0
- package/dist/brain/router/execute.js +84 -0
- package/dist/brain/router/index.d.ts +26 -0
- package/dist/brain/router/index.d.ts.map +1 -0
- package/dist/brain/router/index.js +118 -0
- package/dist/brain/router/routing-memory.d.ts +27 -0
- package/dist/brain/router/routing-memory.d.ts.map +1 -0
- package/dist/brain/router/routing-memory.js +77 -0
- package/dist/brain/router/select.d.ts +32 -0
- package/dist/brain/router/select.d.ts.map +1 -0
- package/dist/brain/router/select.js +146 -0
- package/dist/brain/router/two-hop.d.ts +23 -0
- package/dist/brain/router/two-hop.d.ts.map +1 -0
- package/dist/brain/router/two-hop.js +39 -0
- package/dist/brain/router/verify.d.ts +37 -0
- package/dist/brain/router/verify.d.ts.map +1 -0
- package/dist/brain/router/verify.js +111 -0
- package/dist/brain/types.d.ts +55 -0
- package/dist/brain/types.d.ts.map +1 -0
- package/dist/brain/types.js +16 -0
- package/dist/brain/worker.d.ts +27 -0
- package/dist/brain/worker.d.ts.map +1 -0
- package/dist/brain/worker.js +71 -0
- package/dist/commands/ai.d.ts +24 -0
- package/dist/commands/ai.d.ts.map +1 -0
- package/dist/commands/ai.js +137 -0
- package/dist/commands/alerts.d.ts +19 -0
- package/dist/commands/alerts.d.ts.map +1 -0
- package/dist/commands/alerts.js +114 -0
- package/dist/commands/billing.d.ts +13 -0
- package/dist/commands/billing.d.ts.map +1 -0
- package/dist/commands/billing.js +55 -0
- package/dist/commands/chat.d.ts +22 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +422 -0
- package/dist/commands/config.d.ts +18 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +136 -0
- package/dist/commands/doctor.d.ts +11 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +73 -0
- package/dist/commands/global.d.ts +11 -0
- package/dist/commands/global.d.ts.map +1 -0
- package/dist/commands/global.js +253 -0
- package/dist/commands/keep.d.ts +12 -0
- package/dist/commands/keep.d.ts.map +1 -0
- package/dist/commands/keep.js +58 -0
- package/dist/commands/lifecycle.d.ts +17 -0
- package/dist/commands/lifecycle.d.ts.map +1 -0
- package/dist/commands/lifecycle.js +267 -0
- package/dist/commands/login.d.ts +16 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +234 -0
- package/dist/commands/maintenance.d.ts +12 -0
- package/dist/commands/maintenance.d.ts.map +1 -0
- package/dist/commands/maintenance.js +76 -0
- package/dist/commands/mcp.d.ts +16 -0
- package/dist/commands/mcp.d.ts.map +1 -0
- package/dist/commands/mcp.js +56 -0
- package/dist/commands/memory.d.ts +13 -0
- package/dist/commands/memory.d.ts.map +1 -0
- package/dist/commands/memory.js +218 -0
- package/dist/commands/osint.d.ts +14 -0
- package/dist/commands/osint.d.ts.map +1 -0
- package/dist/commands/osint.js +161 -0
- package/dist/commands/pentest.d.ts +13 -0
- package/dist/commands/pentest.d.ts.map +1 -0
- package/dist/commands/pentest.js +131 -0
- package/dist/commands/scale.d.ts +14 -0
- package/dist/commands/scale.d.ts.map +1 -0
- package/dist/commands/scale.js +191 -0
- package/dist/commands/serve.d.ts +16 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +167 -0
- package/dist/commands/tui.d.ts +17 -0
- package/dist/commands/tui.d.ts.map +1 -0
- package/dist/commands/tui.js +138 -0
- package/dist/commands/wyrm.d.ts +20 -0
- package/dist/commands/wyrm.d.ts.map +1 -0
- package/dist/commands/wyrm.js +274 -0
- package/dist/config.d.ts +67 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +54 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +85 -0
- package/dist/manifest.d.ts +31 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +83 -0
- package/dist/ui.d.ts +57 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +174 -0
- package/dist/utils.d.ts +33 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +155 -0
- package/dist/wyrm/mcp.d.ts +37 -0
- package/dist/wyrm/mcp.d.ts.map +1 -0
- package/dist/wyrm/mcp.js +137 -0
- package/docs/SYSTEM-PREMORTEM.md +397 -0
- package/dragon-manifest.toml +241 -0
- package/dragon.py +177 -0
- package/install/launchd/lk.ghosts.dragonkeep.plist +57 -0
- package/install/systemd/dragonkeep.service +40 -0
- package/media/dragon-silver-lockup.svg +931 -0
- package/media/dragon-silver-mark.svg +931 -0
- package/media/dragon-silver.png +0 -0
- package/package.json +45 -0
- package/specs/001-godmode/constitution.md +54 -0
- package/specs/001-godmode/plan.md +30 -0
- package/specs/001-godmode/spec.md +64 -0
- package/specs/001-godmode/tasks.md +35 -0
- package/specs/002-premortem-positioning/premortem.md +211 -0
- package/src/agent/loop.ts +165 -0
- package/src/agent/mcp.ts +92 -0
- package/src/agent/session.ts +48 -0
- package/src/agent/skills.ts +138 -0
- package/src/agent/stack.ts +154 -0
- package/src/agent/task.ts +55 -0
- package/src/agent/tools.ts +255 -0
- package/src/agent/trace.ts +76 -0
- package/src/agent.ts +114 -0
- package/src/auth.ts +133 -0
- package/src/brain/anthropic.ts +83 -0
- package/src/brain/claude-cli.ts +78 -0
- package/src/brain/ghost-ember.ts +94 -0
- package/src/brain/index.ts +99 -0
- package/src/brain/openai-compat.ts +115 -0
- package/src/brain/router/classify.ts +167 -0
- package/src/brain/router/execute.ts +80 -0
- package/src/brain/router/index.ts +125 -0
- package/src/brain/router/routing-memory.ts +71 -0
- package/src/brain/router/select.ts +156 -0
- package/src/brain/router/two-hop.ts +62 -0
- package/src/brain/router/verify.ts +123 -0
- package/src/brain/types.ts +61 -0
- package/src/brain/worker.ts +72 -0
- package/src/commands/ai.ts +144 -0
- package/src/commands/alerts.ts +131 -0
- package/src/commands/billing.ts +59 -0
- package/src/commands/chat.ts +318 -0
- package/src/commands/config.ts +137 -0
- package/src/commands/doctor.ts +71 -0
- package/src/commands/global.ts +256 -0
- package/src/commands/keep.ts +67 -0
- package/src/commands/lifecycle.ts +273 -0
- package/src/commands/login.ts +184 -0
- package/src/commands/maintenance.ts +54 -0
- package/src/commands/mcp.ts +57 -0
- package/src/commands/memory.ts +229 -0
- package/src/commands/osint.ts +171 -0
- package/src/commands/pentest.ts +140 -0
- package/src/commands/scale.ts +185 -0
- package/src/commands/serve.ts +171 -0
- package/src/commands/tui.ts +126 -0
- package/src/commands/wyrm.ts +269 -0
- package/src/config.ts +93 -0
- package/src/index.ts +92 -0
- package/src/manifest.ts +104 -0
- package/src/ui.ts +188 -0
- package/src/utils.ts +153 -0
- package/src/wyrm/mcp.ts +130 -0
- package/test/auth.test.ts +70 -0
- package/test/brain.test.ts +39 -0
- package/test/security.test.ts +104 -0
- package/test/skills.test.ts +38 -0
- package/test/ui.test.ts +46 -0
- package/tsconfig.json +19 -0
- package/worker/package-lock.json +1527 -0
- package/worker/package.json +17 -0
- package/worker/src/index.ts +76 -0
- package/worker/tsconfig.json +15 -0
- package/worker/wrangler.toml +26 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
# Dragon Stack · System Pre-Mortem
|
|
2
|
+
|
|
3
|
+
Scope: the **whole stack** under Ghost Protocol's offensive-security
|
|
4
|
+
banner — PhantomDragon AI (engine), PhantomDragon Control (operator
|
|
5
|
+
dashboard), DragonNet (OSINT investigation platform), Phantom Memory
|
|
6
|
+
(persistent engagement memory), Wyrm (cross-tool memory backbone),
|
|
7
|
+
and Dragon CLI (unified shell). This pre-mortem imagines it's 12
|
|
8
|
+
months from now and the integrated stack has been abandoned.
|
|
9
|
+
|
|
10
|
+
This is a *system* pre-mortem. Individual products have their own
|
|
11
|
+
under `~/Git Projects/<product>/docs/PRE-MORTEM.md`. Here we focus on
|
|
12
|
+
what breaks **between** them.
|
|
13
|
+
|
|
14
|
+
> Re-read at every quarterly review, before any cross-tool refactor,
|
|
15
|
+
> and after any incident that crosses product boundaries. Update
|
|
16
|
+
> probabilities as we learn.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## #1 · Cross-system schema drift
|
|
21
|
+
|
|
22
|
+
**Probability: HIGH · Impact: SEVERE**
|
|
23
|
+
|
|
24
|
+
Each product evolves on its own cadence. PhantomDragon's
|
|
25
|
+
`findings.json` shape, DragonNet's `entities` table, Phantom Memory's
|
|
26
|
+
SQLite schema, and Wyrm's `data` records all carry implicit
|
|
27
|
+
contracts. There is no single source of truth and no contract test.
|
|
28
|
+
|
|
29
|
+
**How it kills us:** PhantomDragon v3.6 renames `meta.target` to
|
|
30
|
+
`meta.target_url`. Phantom Memory still reads `meta.target`. The
|
|
31
|
+
`/v1/memory` endpoint silently records empty targets for new scans.
|
|
32
|
+
Three months later, the operator notices "no memory for upalis.com"
|
|
33
|
+
even though they scanned it last week. Trust evaporates.
|
|
34
|
+
|
|
35
|
+
**Controls in v1:**
|
|
36
|
+
- Phantom Memory uses defensive `data.get("meta", {}).get(...)` so a
|
|
37
|
+
field rename produces nulls, not crashes.
|
|
38
|
+
- The dragon CLI's `dragon status` could compare versions across
|
|
39
|
+
products (not yet implemented).
|
|
40
|
+
|
|
41
|
+
**Mitigations deferred:**
|
|
42
|
+
- A single canonical schema package (e.g. `@dragon/shared-schemas`)
|
|
43
|
+
imported by every product. Engine emits via Pydantic, dashboards
|
|
44
|
+
consume via TypeScript types generated from JSON Schema.
|
|
45
|
+
- `dragon doctor` contract test that runs sample data from each
|
|
46
|
+
product's outputs through the other products' parsers; fails
|
|
47
|
+
CI when shapes mismatch.
|
|
48
|
+
- A version field in every persisted record (`meta.schema_version`)
|
|
49
|
+
with explicit upgrade paths.
|
|
50
|
+
|
|
51
|
+
**Death-avoidance metric:** Days since a schema field rename
|
|
52
|
+
without coordinating updates across all consumers. >0 days =
|
|
53
|
+
yellow; >7 days = red.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## #2 · The unified-CLI mirage
|
|
58
|
+
|
|
59
|
+
**Probability: HIGH · Impact: MEDIUM**
|
|
60
|
+
|
|
61
|
+
`dragon` exists. But if operators settle into Tool A's native UI
|
|
62
|
+
(PhantomDragon Control's dashboard) and Tool B's native CLI
|
|
63
|
+
(PhantomDragon's `phantomdragon.py`), the unified CLI never gets the
|
|
64
|
+
exercise it needs. Bug rot sets in. The cross-tool flows that only
|
|
65
|
+
the CLI knows about silently break.
|
|
66
|
+
|
|
67
|
+
**How it kills us:** Six months in, `dragon scan` has rotted because
|
|
68
|
+
the PhantomDragon CLI has new flags the wrapper doesn't pass through.
|
|
69
|
+
`dragon osint` doesn't exist because no one needed it badly enough
|
|
70
|
+
to add it. Operators conclude the CLI was a nice idea that didn't
|
|
71
|
+
land.
|
|
72
|
+
|
|
73
|
+
**Controls in v1:**
|
|
74
|
+
- Dragon CLI is the *recommended* entry point in the onboarding
|
|
75
|
+
doc.
|
|
76
|
+
- `dragon scan` flags mirror the engine's flag surface 1:1.
|
|
77
|
+
|
|
78
|
+
**Mitigations deferred:**
|
|
79
|
+
- The dragon CLI should be the **only** documented entry point in
|
|
80
|
+
external docs (README, blog posts, customer-facing). Native
|
|
81
|
+
binaries remain available but are internal.
|
|
82
|
+
- `dragon up` one-command bootstrap so new operators never know
|
|
83
|
+
the underlying ports.
|
|
84
|
+
- `dragon status` becomes the canonical "is everything OK" view —
|
|
85
|
+
no operator should ever need to `ss -tlnp | grep`.
|
|
86
|
+
|
|
87
|
+
**Death-avoidance metric:** Ratio of CLI invocations to native
|
|
88
|
+
binary invocations across operator sessions. Target ≥3:1 by month 3.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## #3 · Two memory systems, one operator
|
|
93
|
+
|
|
94
|
+
**Probability: HIGH · Impact: HIGH**
|
|
95
|
+
|
|
96
|
+
Phantom Memory (`~/.copilot/phantom-memory.db`, SQLite) and Wyrm
|
|
97
|
+
(`~/.copilot/session-store.db`, also SQLite + HTTP :3333) both claim
|
|
98
|
+
to be the cross-tool memory store. Today they don't overlap — Phantom
|
|
99
|
+
Memory holds scan/OSINT/credential data, Wyrm holds session/quest/
|
|
100
|
+
context data. But the boundary is fuzzy.
|
|
101
|
+
|
|
102
|
+
**How it kills us:** A future feature wants to query "what targets
|
|
103
|
+
has Ryan worked on this quarter?" — both DBs have a partial answer.
|
|
104
|
+
The query is built against Wyrm. Two months later someone builds
|
|
105
|
+
the same query against Phantom Memory because they didn't know
|
|
106
|
+
Wyrm had it. Two truths, no reconciliation, and now the AI brain
|
|
107
|
+
gets *different* context depending on which path it took.
|
|
108
|
+
|
|
109
|
+
**Controls in v1:**
|
|
110
|
+
- Phantom Memory is documented as "scan + OSINT + creds";
|
|
111
|
+
Wyrm is "sessions + quests + decisions". Different concerns.
|
|
112
|
+
|
|
113
|
+
**Mitigations deferred:**
|
|
114
|
+
- One-paragraph "where data lives" doc in `dragon-cli/docs/`.
|
|
115
|
+
- A federated query endpoint (`dragon memory query "..."` that hits
|
|
116
|
+
both stores and merges results with provenance).
|
|
117
|
+
- A long-term decision: either fold Phantom Memory *into* Wyrm
|
|
118
|
+
as a new entity kind, or extract Wyrm's session/quest layer
|
|
119
|
+
into Phantom Memory. One store, two access paths.
|
|
120
|
+
|
|
121
|
+
**Death-avoidance metric:** Number of queries that get a different
|
|
122
|
+
answer from Phantom Memory vs Wyrm for the same logical question.
|
|
123
|
+
Should be 0.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## #4 · No multi-tenant isolation
|
|
128
|
+
|
|
129
|
+
**Probability: MEDIUM · Impact: SEVERE (for PTaaS)**
|
|
130
|
+
|
|
131
|
+
PhantomDragon Control's `reports/` is single-operator. Phantom Memory
|
|
132
|
+
is single-DB. DragonNet has investigation membership and roles
|
|
133
|
+
(good) but no account isolation at the DB level. The day Ghost
|
|
134
|
+
Protocol takes its second PTaaS customer, this becomes a problem.
|
|
135
|
+
|
|
136
|
+
**How it kills us:** Customer A logs in and sees scans that include
|
|
137
|
+
PII from Customer B's penetration test (because Phantom Memory's
|
|
138
|
+
"all targets" view doesn't know about tenancy). One incident →
|
|
139
|
+
contract terminated, GDPR exposure, reputational hit.
|
|
140
|
+
|
|
141
|
+
**Controls in v1:**
|
|
142
|
+
- Deploys are explicitly single-operator. No customer is live yet.
|
|
143
|
+
- PhantomDragon PTaaS (separate spec-kit project at
|
|
144
|
+
`~/Git Projects/phantomdragon-ptaas/`) does account-level isolation
|
|
145
|
+
in its own DB.
|
|
146
|
+
|
|
147
|
+
**Mitigations deferred:**
|
|
148
|
+
- Phantom Memory gains an `operator_id` / `tenant_id` foreign key
|
|
149
|
+
on every table.
|
|
150
|
+
- PhantomDragon Control gains auth + per-operator reports/ dir
|
|
151
|
+
before any external deploy.
|
|
152
|
+
- The dragon CLI carries a `--operator` context that gates queries.
|
|
153
|
+
|
|
154
|
+
**Death-avoidance metric:** Days until first non-Ryan operator gets
|
|
155
|
+
access to the stack. Becomes red the moment that's <30 days away
|
|
156
|
+
without multi-tenant work shipped.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## #5 · Single-laptop disaster
|
|
161
|
+
|
|
162
|
+
**Probability: MEDIUM · Impact: SEVERE**
|
|
163
|
+
|
|
164
|
+
The entire engagement memory — every scan finding, every OSINT
|
|
165
|
+
entity, every credential exposure across years — lives in one
|
|
166
|
+
SQLite file on Ryan's laptop. Disk failure = years gone.
|
|
167
|
+
|
|
168
|
+
**How it kills us:** Laptop dies. Ryan reformats. Phantom Memory
|
|
169
|
+
was "going to be backed up next week." Engagements with paying
|
|
170
|
+
customers reference finding IDs that are now permanently lost.
|
|
171
|
+
|
|
172
|
+
**Controls in v1:**
|
|
173
|
+
- Wyrm has R2 cloud backup (Wyrm task #171).
|
|
174
|
+
- `reports/` is a git-tracked directory in some cases.
|
|
175
|
+
|
|
176
|
+
**Mitigations deferred:**
|
|
177
|
+
- `dragon backup` command that snapshots Phantom Memory + reports/
|
|
178
|
+
+ DragonNet's Postgres dump + Wyrm DB to encrypted R2.
|
|
179
|
+
- Nightly cron via systemd timer (operator opt-in).
|
|
180
|
+
- `dragon restore` for round-trip verification.
|
|
181
|
+
|
|
182
|
+
**Death-avoidance metric:** Days since last successful Phantom
|
|
183
|
+
Memory backup to a different physical drive. <7 = green, 7-30 =
|
|
184
|
+
yellow, >30 = red.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## #6 · Auth fragmentation
|
|
189
|
+
|
|
190
|
+
**Probability: MEDIUM · Impact: MEDIUM**
|
|
191
|
+
|
|
192
|
+
DragonNet: magic-link + JWT + TOTP. PhantomDragon Control: no auth
|
|
193
|
+
(binds to localhost). Wyrm: bearer token from `~/.wyrm/http-config.json`.
|
|
194
|
+
The dragon CLI: trusts the operator's shell.
|
|
195
|
+
|
|
196
|
+
**How it kills us:** First deploy to a LAN — PhantomDragon Control
|
|
197
|
+
suddenly readable by anyone in the office network. The cross-link
|
|
198
|
+
from PhantomDragon Control → DragonNet does *not* pass auth state,
|
|
199
|
+
so the operator has to re-login every time they click "OSINT this".
|
|
200
|
+
That friction means they stop using the integration.
|
|
201
|
+
|
|
202
|
+
**Controls in v1:**
|
|
203
|
+
- Documented as "localhost-only" until auth ships.
|
|
204
|
+
- DragonNet's auth is solid — magic-link + TOTP + JWT session.
|
|
205
|
+
|
|
206
|
+
**Mitigations deferred:**
|
|
207
|
+
- Adopt DragonNet's auth as the canonical layer; PhantomDragon
|
|
208
|
+
Control consumes its sessions via shared cookie.
|
|
209
|
+
- A common origin (`http://localhost:4000` reverse-proxied to all
|
|
210
|
+
services) so the same session cookie applies everywhere.
|
|
211
|
+
- The dragon CLI does an auth handshake on `dragon up`.
|
|
212
|
+
|
|
213
|
+
**Death-avoidance metric:** Days since the stack ran with any
|
|
214
|
+
service bound to 0.0.0.0 without auth. Becomes red the moment any
|
|
215
|
+
such bind exists in production.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## #7 · Darkweb collectors create legal exposure
|
|
220
|
+
|
|
221
|
+
**Probability: MEDIUM · Impact: HIGH**
|
|
222
|
+
|
|
223
|
+
TORWATCH crawls operator-supplied .onion seeds. PASTEDRAGNET probes
|
|
224
|
+
pastebin.com mirrors. TELEGAZER scrapes Telegram public channels.
|
|
225
|
+
NIGHTGLASS reads operator-supplied breach corpora. Each of these is
|
|
226
|
+
defensible on its own — they touch only public previews or operator-
|
|
227
|
+
provided data. But the *combination* could be read by a hostile
|
|
228
|
+
prosecutor as "systematic collection of breach data."
|
|
229
|
+
|
|
230
|
+
**How it kills us:** Sri Lanka's Computer Crimes Act 2007 is broad
|
|
231
|
+
enough that a determined regulator could call any of this "unauthorized
|
|
232
|
+
access" if the seed list includes a credential market URL or the
|
|
233
|
+
breach corpus came from somewhere borderline. Defense cost alone
|
|
234
|
+
sinks Ghost Protocol.
|
|
235
|
+
|
|
236
|
+
**Controls in v1:**
|
|
237
|
+
- Every darkweb collector has an explicit operator-supplied input
|
|
238
|
+
(env var or breach DB).
|
|
239
|
+
- TORWATCH refuses to fetch without an explicit Tor proxy set.
|
|
240
|
+
- No collector invents seeds, channels, or breach data.
|
|
241
|
+
|
|
242
|
+
**Mitigations deferred:**
|
|
243
|
+
- A `dragon legal pre-flight <jurisdiction>` command that prints
|
|
244
|
+
the legal posture for each enabled collector in that
|
|
245
|
+
jurisdiction.
|
|
246
|
+
- Explicit per-investigation consent flag: "I represent that the
|
|
247
|
+
target authorizes this investigation."
|
|
248
|
+
- Tamper-evident audit log of every collector run (already in
|
|
249
|
+
DragonNet's `audit` table; surface it via UI).
|
|
250
|
+
- Geofenced collectors that auto-disable in jurisdictions where
|
|
251
|
+
they're risky (operator-configurable).
|
|
252
|
+
|
|
253
|
+
**Death-avoidance metric:** Number of investigations where a
|
|
254
|
+
darkweb collector ran without an authorization record in the
|
|
255
|
+
audit log. Should be 0.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## #8 · AI brain context bloat
|
|
260
|
+
|
|
261
|
+
**Probability: MEDIUM · Impact: MEDIUM**
|
|
262
|
+
|
|
263
|
+
`phantom_memory.ai_brain_context()` truncates at 4000 chars. For a
|
|
264
|
+
target with 3 scans this is generous. For a target with 50 scans
|
|
265
|
+
across 2 years, 500 OSINT entities, and 1000 credential exposures,
|
|
266
|
+
4000 chars is nowhere near enough. The brain ends up with a
|
|
267
|
+
truncated, randomly-ordered view of history.
|
|
268
|
+
|
|
269
|
+
**How it kills us:** A heavy long-term target's scan produces worse
|
|
270
|
+
results in month 18 than in month 1 because the context system can't
|
|
271
|
+
prioritize what matters. Operator concludes "the AI got dumber"
|
|
272
|
+
when actually we got smarter — we just don't know how to use the
|
|
273
|
+
extra knowledge.
|
|
274
|
+
|
|
275
|
+
**Controls in v1:**
|
|
276
|
+
- 4000-char cap is documented as MVP.
|
|
277
|
+
- Persistent findings + last-resolved are surfaced first
|
|
278
|
+
(highest signal).
|
|
279
|
+
|
|
280
|
+
**Mitigations deferred:**
|
|
281
|
+
- Tiered context: critical findings → high → medium-recency tech →
|
|
282
|
+
recent OSINT → credential exposures. Each tier has its own cap.
|
|
283
|
+
- Vector embeddings on findings so the brain pulls semantically
|
|
284
|
+
relevant prior findings, not just chronological ones.
|
|
285
|
+
- A `dragon memory context <target> --max-tokens N` flag for
|
|
286
|
+
larger budgets.
|
|
287
|
+
|
|
288
|
+
**Death-avoidance metric:** Average char usage of brain context as
|
|
289
|
+
% of cap. >85% means we're saturating; should expand or tier.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## #9 · Cross-tool data flow has no replay
|
|
294
|
+
|
|
295
|
+
**Probability: LOW · Impact: HIGH**
|
|
296
|
+
|
|
297
|
+
When PhantomDragon Control pushes a scan to Phantom Memory and
|
|
298
|
+
Phantom Memory pushes to Wyrm, the flow is fire-and-forget. If any
|
|
299
|
+
step fails (Phantom Memory disk full, Wyrm offline, network blip),
|
|
300
|
+
data silently goes missing. No queue. No retry.
|
|
301
|
+
|
|
302
|
+
**How it kills us:** Disk-full or Wyrm offline for an hour during a
|
|
303
|
+
scan. The scan completes successfully in PhantomDragon's reports/.
|
|
304
|
+
Phantom Memory ingestion fails silently. Operator notices weeks
|
|
305
|
+
later that "memory has gaps." Cannot reconstruct which scans were
|
|
306
|
+
ingested without parsing every reports/ dir against memory.
|
|
307
|
+
|
|
308
|
+
**Controls in v1:**
|
|
309
|
+
- `phantom_memory.ingest_reports_dir()` is idempotent — re-running
|
|
310
|
+
recovers any missed scans.
|
|
311
|
+
- The `control_api.py` startup auto-runs `ingest_reports_dir()`.
|
|
312
|
+
|
|
313
|
+
**Mitigations deferred:**
|
|
314
|
+
- A persistent retry queue (`~/.copilot/phantom-memory-queue.json`)
|
|
315
|
+
for failed pushes to Wyrm.
|
|
316
|
+
- `dragon memory verify` command that diffs reports/ against
|
|
317
|
+
Phantom Memory and reports any gaps.
|
|
318
|
+
- `dragon memory reingest --since 2026-04-01` for time-bounded
|
|
319
|
+
recovery.
|
|
320
|
+
|
|
321
|
+
**Death-avoidance metric:** Count of reports/ scans not present in
|
|
322
|
+
Phantom Memory after a `dragon status memory` check. Should be 0.
|
|
323
|
+
|
|
324
|
+
---
|
|
325
|
+
|
|
326
|
+
## #10 · Operator-onboarding cliff
|
|
327
|
+
|
|
328
|
+
**Probability: LOW · Impact: HIGH (if hiring)**
|
|
329
|
+
|
|
330
|
+
The stack assumes the operator (Ryan) built it. A new operator
|
|
331
|
+
joining tomorrow would face: 3 repos to clone, 5 services to start,
|
|
332
|
+
2 database systems to migrate, 1 unified CLI to install but with
|
|
333
|
+
spotty docs, and a mental model that lives only in Ryan's head.
|
|
334
|
+
|
|
335
|
+
**How it kills us:** Ghost Protocol hires a second operator. They
|
|
336
|
+
spend 3 days getting the local stack running. They never quite
|
|
337
|
+
understand which features go through which dashboard. They produce
|
|
338
|
+
slower, worse engagements for the first month. Either Ryan refuses
|
|
339
|
+
to hire again, or the new operator quits.
|
|
340
|
+
|
|
341
|
+
**Controls in v1:**
|
|
342
|
+
- `dragon init` auto-detects product paths.
|
|
343
|
+
- This pre-mortem + the skills under `~/.copilot/skills/` exist.
|
|
344
|
+
|
|
345
|
+
**Mitigations deferred:**
|
|
346
|
+
- `dragon up` one-command bootstrap (clones missing repos, runs
|
|
347
|
+
migrations, starts services, opens the dashboard).
|
|
348
|
+
- A 1-page operator playbook ("here's how an engagement flows
|
|
349
|
+
through the stack").
|
|
350
|
+
- Onboarding video / Loom (operator-facing, 10 min).
|
|
351
|
+
- `dragon doctor` to verify the local install matches the
|
|
352
|
+
reference shape.
|
|
353
|
+
|
|
354
|
+
**Death-avoidance metric:** Time-to-first-real-scan for a new
|
|
355
|
+
operator. Target < 30 minutes from `git clone dragon-cli` to a
|
|
356
|
+
successful `dragon scan example.com`.
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Death-avoidance dashboard
|
|
361
|
+
|
|
362
|
+
Track monthly. Anything red triggers a remediation session.
|
|
363
|
+
|
|
364
|
+
| Metric | Green | Yellow | Red |
|
|
365
|
+
|---|---|---|---|
|
|
366
|
+
| Days since cross-tool schema rename without coordination | 0 | 1-7 | >7 |
|
|
367
|
+
| Ratio of dragon-CLI to native-CLI invocations | ≥3:1 | 1-3:1 | <1:1 |
|
|
368
|
+
| Phantom Memory vs Wyrm divergence for same logical query | 0 | 1-3 | >3 |
|
|
369
|
+
| Days until first non-Ryan operator | >30 | 7-30 | <7 |
|
|
370
|
+
| Days since last Phantom Memory backup to second drive | <7 | 7-30 | >30 |
|
|
371
|
+
| Days running 0.0.0.0 without auth | 0 (localhost only) | — | any |
|
|
372
|
+
| Investigations with darkweb collectors lacking authorization record | 0 | 1-3 | >3 |
|
|
373
|
+
| Avg brain-context char usage as % of cap | <70% | 70-90% | >90% |
|
|
374
|
+
| Reports not present in Phantom Memory after status check | 0 | 1-3 | >3 |
|
|
375
|
+
| Time-to-first-scan for new operator | <30min | 30-90min | >90min |
|
|
376
|
+
|
|
377
|
+
## Re-read schedule
|
|
378
|
+
|
|
379
|
+
- Every quarterly review
|
|
380
|
+
- Before any cross-tool refactor
|
|
381
|
+
- After any incident crossing product boundaries
|
|
382
|
+
- When any metric crosses into yellow
|
|
383
|
+
|
|
384
|
+
## The single thread
|
|
385
|
+
|
|
386
|
+
Eight of these ten causes-of-death converge on the same root: **the
|
|
387
|
+
stack treats its products as independent, but operators experience
|
|
388
|
+
them as one system.** Schema drift, the CLI mirage, the two-memory
|
|
389
|
+
problem, auth fragmentation, AI context bloat, the data-flow replay
|
|
390
|
+
gap, and the onboarding cliff all stem from missing federation
|
|
391
|
+
discipline.
|
|
392
|
+
|
|
393
|
+
The fix is structural, not feature-by-feature: **the dragon CLI must
|
|
394
|
+
be the federation layer.** Every cross-tool flow goes through it.
|
|
395
|
+
Every health check, every backup, every schema contract, every auth
|
|
396
|
+
handshake. The CLI is not a convenience — it's the integration
|
|
397
|
+
substrate.
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# Ghost Protocol · Dragon Stack Manifest
|
|
2
|
+
# Declares every product in the stack so `dragon up`, `dragon update`,
|
|
3
|
+
# `dragon install`, and `dragon stop` can manage the whole portfolio
|
|
4
|
+
# from a single command.
|
|
5
|
+
#
|
|
6
|
+
# Copyright 2026 Ghost Protocol (Pvt) Ltd. All Rights Reserved.
|
|
7
|
+
# Author: Ryan Sebastian <ryan@ghosts.lk>
|
|
8
|
+
|
|
9
|
+
manifest_version = "1.0"
|
|
10
|
+
default_root = "~/Git Projects"
|
|
11
|
+
|
|
12
|
+
# Each [[product]] entry declares:
|
|
13
|
+
# key - short slug used by `dragon install <key>` etc.
|
|
14
|
+
# name - display name
|
|
15
|
+
# repo - GitHub repo (owner/name)
|
|
16
|
+
# dir - local checkout dir name (under default_root)
|
|
17
|
+
# stack - "operator" | "commercial" | "daemon" | "library"
|
|
18
|
+
# kind - "rust" | "node" | "python" | "monorepo" | "docker"
|
|
19
|
+
# install - command(s) to bring up the local install
|
|
20
|
+
# start - command to start the runtime (optional)
|
|
21
|
+
# stop - command/signal to stop it (optional)
|
|
22
|
+
# port - service port if applicable
|
|
23
|
+
# requires - list of other product keys that MUST be installed first
|
|
24
|
+
|
|
25
|
+
# ── Operator stack ────────────────────────────────────────────────
|
|
26
|
+
|
|
27
|
+
[[product]]
|
|
28
|
+
key = "phantom-dragon-ai"
|
|
29
|
+
name = "PhantomDragon AI"
|
|
30
|
+
repo = "Ghosts-Protocol-Pvt-Ltd/phantom-dragon-ai"
|
|
31
|
+
dir = "Phantom Dragon AI"
|
|
32
|
+
stack = "operator"
|
|
33
|
+
kind = "python"
|
|
34
|
+
install = ["pip install -e ."]
|
|
35
|
+
start = "python3 -m phantom_dragon_ai.control_api"
|
|
36
|
+
port = 4091
|
|
37
|
+
|
|
38
|
+
[[product]]
|
|
39
|
+
key = "dragon-console"
|
|
40
|
+
name = "Dragon Console"
|
|
41
|
+
repo = "ghosts-lk/dragon-console"
|
|
42
|
+
dir = "phantomdragon-control"
|
|
43
|
+
stack = "operator"
|
|
44
|
+
kind = "node"
|
|
45
|
+
install = ["npm install"]
|
|
46
|
+
start = "npm run dev"
|
|
47
|
+
port = 4090
|
|
48
|
+
requires = ["phantom-dragon-ai"]
|
|
49
|
+
# Dragon Console is the GUI sibling of the `dragon` CLI — houses
|
|
50
|
+
# PhantomDragon (offensive), Phantom Memory, DragonNet (cross-link),
|
|
51
|
+
# DragonKeep (cross-link + defensive queue view), and commercial
|
|
52
|
+
# modules. Local dir stays "phantomdragon-control" until the repo is
|
|
53
|
+
# renamed on GitHub (gh repo rename ghosts-lk/dragon-console).
|
|
54
|
+
|
|
55
|
+
[[product]]
|
|
56
|
+
key = "dragonhunt"
|
|
57
|
+
name = "DragonHunt (lead-gen)"
|
|
58
|
+
repo = "Ghosts-Protocol-Pvt-Ltd/DragonHunt"
|
|
59
|
+
dir = "DragonHunt"
|
|
60
|
+
stack = "operator"
|
|
61
|
+
kind = "node"
|
|
62
|
+
install = ["npm install"]
|
|
63
|
+
# Reads ./.env (JWT_SECRET, PD_API, port). The 'safe' scan posture calls
|
|
64
|
+
# control_api at :4091, so phantom-dragon-ai must be up first. Dragon Console
|
|
65
|
+
# proxies to this at :3334 with DRAGONHUNT_TOKEN (see its .env.local).
|
|
66
|
+
start = "npm run dev"
|
|
67
|
+
port = 3334
|
|
68
|
+
requires = ["phantom-dragon-ai"]
|
|
69
|
+
|
|
70
|
+
[[product]]
|
|
71
|
+
key = "dragonnet"
|
|
72
|
+
name = "DragonNet OSINT API"
|
|
73
|
+
repo = "ghosts-lk/dragonnet"
|
|
74
|
+
dir = "DragonNet"
|
|
75
|
+
stack = "operator"
|
|
76
|
+
kind = "monorepo"
|
|
77
|
+
install = ["pnpm install"]
|
|
78
|
+
# Dashboard at :4081 is deprecated as of 2026-05-23 — its UI lives
|
|
79
|
+
# inside Dragon Console under /investigations now. We only start the
|
|
80
|
+
# Fastify API at :4080 going forward.
|
|
81
|
+
start = "pnpm --filter @dragonnet/api dev"
|
|
82
|
+
port = 4080
|
|
83
|
+
|
|
84
|
+
[[product]]
|
|
85
|
+
key = "dragonkeep"
|
|
86
|
+
name = "DragonKeep"
|
|
87
|
+
repo = "Ghosts-Protocol-Pvt-Ltd/DragonKeep"
|
|
88
|
+
dir = "DragonKeep"
|
|
89
|
+
stack = "operator"
|
|
90
|
+
kind = "rust"
|
|
91
|
+
install = ["cargo build --release"]
|
|
92
|
+
start = "./target/release/dragonkeep monitor"
|
|
93
|
+
|
|
94
|
+
[[product]]
|
|
95
|
+
key = "dragon-cli"
|
|
96
|
+
name = "Dragon CLI"
|
|
97
|
+
repo = "ghosts-lk/dragon-cli"
|
|
98
|
+
dir = "dragon-cli"
|
|
99
|
+
stack = "operator"
|
|
100
|
+
kind = "node"
|
|
101
|
+
install = ["npm install", "npm run build", "npm link"]
|
|
102
|
+
|
|
103
|
+
[[product]]
|
|
104
|
+
key = "dragonchronicle"
|
|
105
|
+
name = "DragonChronicle"
|
|
106
|
+
repo = "ghosts-lk/dragonchronicle"
|
|
107
|
+
dir = "DragonChronicle"
|
|
108
|
+
stack = "library"
|
|
109
|
+
kind = "python"
|
|
110
|
+
install = ["pip install -e ."]
|
|
111
|
+
|
|
112
|
+
[[product]]
|
|
113
|
+
key = "dragonscan-sdk"
|
|
114
|
+
name = "DragonScan SDK"
|
|
115
|
+
repo = "ghosts-lk/dragonscansdk"
|
|
116
|
+
dir = "DragonScanSDK"
|
|
117
|
+
stack = "library"
|
|
118
|
+
kind = "python"
|
|
119
|
+
install = ["pip install -e ."]
|
|
120
|
+
|
|
121
|
+
[[product]]
|
|
122
|
+
key = "dragonagent"
|
|
123
|
+
name = "DragonAgent"
|
|
124
|
+
repo = "ghosts-lk/dragonagent"
|
|
125
|
+
dir = "DragonAgent"
|
|
126
|
+
stack = "library"
|
|
127
|
+
kind = "python"
|
|
128
|
+
install = ["pip install -e ."]
|
|
129
|
+
requires = ["dragonscan-sdk"]
|
|
130
|
+
|
|
131
|
+
[[product]]
|
|
132
|
+
key = "dragonpilot"
|
|
133
|
+
name = "DragonPilot"
|
|
134
|
+
repo = "ghosts-lk/dragonpilot"
|
|
135
|
+
dir = "DragonPilot"
|
|
136
|
+
stack = "library"
|
|
137
|
+
kind = "node"
|
|
138
|
+
install = ["npm link"]
|
|
139
|
+
|
|
140
|
+
[[product]]
|
|
141
|
+
key = "dragonlens"
|
|
142
|
+
name = "DragonLens VS Code"
|
|
143
|
+
repo = "ghosts-lk/dragonlens"
|
|
144
|
+
dir = "DragonLens"
|
|
145
|
+
stack = "library"
|
|
146
|
+
kind = "node"
|
|
147
|
+
install = ["npm install", "npm run compile"]
|
|
148
|
+
|
|
149
|
+
# ── MCP servers ───────────────────────────────────────────────────
|
|
150
|
+
|
|
151
|
+
[[product]]
|
|
152
|
+
key = "phantom-memory-mcp"
|
|
153
|
+
name = "Phantom Memory MCP"
|
|
154
|
+
repo = "ghosts-lk/phantom-memory-mcp"
|
|
155
|
+
dir = "phantom-memory-mcp"
|
|
156
|
+
stack = "daemon"
|
|
157
|
+
kind = "python"
|
|
158
|
+
install = ["pip install -e ."]
|
|
159
|
+
|
|
160
|
+
[[product]]
|
|
161
|
+
key = "dragonkeep-mcp"
|
|
162
|
+
name = "DragonKeep MCP"
|
|
163
|
+
repo = "ghosts-lk/dragonkeep-mcp"
|
|
164
|
+
dir = "dragonkeep-mcp"
|
|
165
|
+
stack = "daemon"
|
|
166
|
+
kind = "python"
|
|
167
|
+
install = ["pip install -e ."]
|
|
168
|
+
|
|
169
|
+
[[product]]
|
|
170
|
+
key = "dragonnet-mcp"
|
|
171
|
+
name = "DragonNet MCP"
|
|
172
|
+
repo = "ghosts-lk/dragonnet-mcp"
|
|
173
|
+
dir = "dragonnet-mcp"
|
|
174
|
+
stack = "daemon"
|
|
175
|
+
kind = "python"
|
|
176
|
+
install = ["pip install -e ."]
|
|
177
|
+
|
|
178
|
+
[[product]]
|
|
179
|
+
key = "dragon-meta-mcp"
|
|
180
|
+
name = "Dragon Meta MCP"
|
|
181
|
+
repo = "ghosts-lk/dragon-meta-mcp"
|
|
182
|
+
dir = "dragon-meta-mcp"
|
|
183
|
+
stack = "daemon"
|
|
184
|
+
kind = "python"
|
|
185
|
+
install = ["pip install -e ."]
|
|
186
|
+
requires = ["phantom-memory-mcp", "dragonkeep-mcp", "dragonnet-mcp"]
|
|
187
|
+
|
|
188
|
+
# ── Commercial stack ──────────────────────────────────────────────
|
|
189
|
+
|
|
190
|
+
[[product]]
|
|
191
|
+
key = "phantomdragon-ptaas"
|
|
192
|
+
name = "PhantomDragon PTaaS"
|
|
193
|
+
repo = "ghosts-lk/phantomdragon-ptaas"
|
|
194
|
+
dir = "phantomdragon-ptaas"
|
|
195
|
+
stack = "commercial"
|
|
196
|
+
kind = "monorepo"
|
|
197
|
+
install = ["pnpm install"]
|
|
198
|
+
start = "pnpm dev"
|
|
199
|
+
port = 4092
|
|
200
|
+
|
|
201
|
+
[[product]]
|
|
202
|
+
key = "dragonscribe"
|
|
203
|
+
name = "DragonScribe"
|
|
204
|
+
repo = "ghosts-lk/dragonscribe"
|
|
205
|
+
dir = "dragonscribe"
|
|
206
|
+
stack = "commercial"
|
|
207
|
+
kind = "monorepo"
|
|
208
|
+
install = ["pnpm install"]
|
|
209
|
+
start = "pnpm dev"
|
|
210
|
+
port = 4093
|
|
211
|
+
|
|
212
|
+
[[product]]
|
|
213
|
+
key = "dragonreef"
|
|
214
|
+
name = "DragonReef"
|
|
215
|
+
repo = "ghosts-lk/dragonreef"
|
|
216
|
+
dir = "dragonreef"
|
|
217
|
+
stack = "commercial"
|
|
218
|
+
kind = "monorepo"
|
|
219
|
+
install = ["pnpm install"]
|
|
220
|
+
start = "pnpm dev"
|
|
221
|
+
port = 4094
|
|
222
|
+
|
|
223
|
+
# ── Memory backbone ───────────────────────────────────────────────
|
|
224
|
+
|
|
225
|
+
[[product]]
|
|
226
|
+
key = "wyrm"
|
|
227
|
+
name = "Wyrm MCP"
|
|
228
|
+
repo = "ghosts-lk/Wyrm"
|
|
229
|
+
dir = "Wyrm"
|
|
230
|
+
stack = "daemon"
|
|
231
|
+
kind = "monorepo"
|
|
232
|
+
# Wyrm has no root package.json or pnpm workspace — install + build run
|
|
233
|
+
# inside packages/mcp-server. (Earlier `pnpm install` / `pnpm build`
|
|
234
|
+
# entries silently no-op'd here and made `dragon up` look successful
|
|
235
|
+
# while leaving Wyrm uninstalled.)
|
|
236
|
+
install = [
|
|
237
|
+
"npm install --prefix packages/mcp-server",
|
|
238
|
+
"npm run build --prefix packages/mcp-server",
|
|
239
|
+
]
|
|
240
|
+
start = "node packages/mcp-server/dist/http-server.js"
|
|
241
|
+
port = 3333
|