delimit-cli 3.15.14 → 4.0.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.
@@ -19,9 +19,8 @@ All tools follow the Adapter Boundary Contract v1.0:
19
19
  - Stateless between calls
20
20
  """
21
21
 
22
- # ── Founder Voice Doctrine ──────────────────────────────────────────────
22
+ # ── Output Quality Rules ──────────────────────────────────────────────
23
23
  # Applies to ALL outward-facing text generated by any tool in this server.
24
- # Full doctrine: /home/delimit/delimit-private/style/FOUNDER_VOICE_DOCTRINE.md
25
24
  #
26
25
  # Core: serious builder/operator, not a marketer. Credibility over persuasion.
27
26
  # Truth over excitement. Concrete mechanisms, not vague benefits.
@@ -34,14 +33,7 @@ All tools follow the Adapter Boundary Contract v1.0:
34
33
  # attached to decisions? Would this still read well a year from now?
35
34
  # ────────────────────────────────────────────────────────────────────────
36
35
 
37
- FOUNDER_VOICE_HYPE_WORDS = {
38
- "revolutionary", "game-changing", "world-class", "cutting-edge",
39
- "best-in-class", "seamless", "unlock", "supercharge", "next-generation",
40
- "magical", "delightful", "effortless", "frictionless", "transformative",
41
- "paradigm shift", "visionary", "category-defining", "industry-leading",
42
- "innovative", "reimagine", "future of", "changing the game",
43
- "empowering teams", "built for everyone",
44
- }
36
+ # Output quality rules loaded from user config at runtime.
45
37
 
46
38
  import json
47
39
  import logging
@@ -60,13 +52,13 @@ from fastmcp import FastMCP
60
52
  logger = logging.getLogger("delimit.ai")
61
53
 
62
54
  # ═══════════════════════════════════════════════════════════════════════
63
- # STR-046: Agent Identity — session tracking for every tool call
55
+ # TASK: Agent Identity — session tracking for every tool call
64
56
  # ═══════════════════════════════════════════════════════════════════════
65
57
 
66
58
  _current_session_id = os.environ.get("DELIMIT_SESSION_ID", "")
67
59
 
68
60
  # ═══════════════════════════════════════════════════════════════════════
69
- # STR-053: Distributed Tracing — trace ID + span counter for every call
61
+ # TASK: Distributed Tracing — trace ID + span counter for every call
70
62
  # ═══════════════════════════════════════════════════════════════════════
71
63
 
72
64
  _trace_id = os.environ.get("DELIMIT_TRACE_ID", str(uuid.uuid4())[:8])
@@ -251,7 +243,7 @@ def _coerce_dict_arg(
251
243
 
252
244
 
253
245
  # ═══════════════════════════════════════════════════════════════════════
254
- # STR-040: Risk Classification for Approval Gates
246
+ # TASK: Risk Classification for Approval Gates
255
247
  # ═══════════════════════════════════════════════════════════════════════
256
248
 
257
249
  HIGH_RISK_TOOLS = {
@@ -275,7 +267,7 @@ def _classify_risk(tool_name: str) -> str:
275
267
 
276
268
 
277
269
  # ═══════════════════════════════════════════════════════════════════════
278
- # STR-052: Policy Kernel — Inline Enforcement
270
+ # TASK: Policy Kernel — Inline Enforcement
279
271
  # Checks policy BEFORE/AFTER tool execution to block high-risk actions.
280
272
  # ═══════════════════════════════════════════════════════════════════════
281
273
 
@@ -327,7 +319,7 @@ def _check_policy_gate(tool_name: str, kwargs: dict) -> Optional[Dict]:
327
319
  "action": "Switch to guarded mode or request approval",
328
320
  }
329
321
 
330
- # LED-173: Deploy gating — block deploys when unresolved critical findings exist
322
+ # TASK: Deploy gating — block deploys when unresolved critical findings exist
331
323
  DEPLOY_TOOLS = {"deploy_publish", "deploy_npm", "deploy_site", "deploy_build"}
332
324
  clean = tool_name.replace("delimit_", "")
333
325
  if clean in DEPLOY_TOOLS and mode != "advisory":
@@ -455,7 +447,7 @@ mcp.description = (
455
447
 
456
448
  VERSION = "3.2.1"
457
449
 
458
- # LED-044 + Consensus 118/119/120: Tool visibility tiers.
450
+ # TASK + Consensus 118/119/120: Tool visibility tiers.
459
451
  # Tier cascade: SHOW_EXPERIMENTAL > SHOW_INTERNAL > SHOW_OPS > public (always visible).
460
452
  # Set DELIMIT_SHOW_INTERNAL=1 to see all tiers (founder workflow).
461
453
  SHOW_EXPERIMENTAL = os.environ.get("DELIMIT_SHOW_EXPERIMENTAL", "") == "1"
@@ -840,7 +832,7 @@ NEXT_STEPS_REGISTRY: Dict[str, List[Dict[str, Any]]] = {
840
832
  ],
841
833
  # --- Sensing ---
842
834
  "sensor_github_issue": [],
843
- # --- Context Filesystem (STR-048) ---
835
+ # --- Context Filesystem (TASK) ---
844
836
  "context_init": [
845
837
  {"tool": "delimit_context_write", "reason": "Write an artifact to the new context", "suggested_args": {}, "is_premium": False},
846
838
  ],
@@ -966,10 +958,10 @@ def _emit_event(tool_name: str, result: Dict[str, Any]) -> None:
966
958
  except Exception:
967
959
  pass # Never let cloud sync break tool execution
968
960
 
969
- # LED-183: Webhook notifications for governance events
961
+ # TASK: Webhook notifications for governance events
970
962
  _fire_webhook(event)
971
963
 
972
- # STR-053: Write trace span for session replay
964
+ # TASK: Write trace span for session replay
973
965
  try:
974
966
  from ai.tracing import start_span, end_span
975
967
  span = start_span(_trace_id, tool_name, args={"tool": tool_name})
@@ -981,7 +973,7 @@ def _emit_event(tool_name: str, result: Dict[str, Any]) -> None:
981
973
  except Exception:
982
974
  pass # Tracing is best-effort
983
975
 
984
- # STR-046: Write to agent_actions log for session drill-down
976
+ # TASK: Write to agent_actions log for session drill-down
985
977
  if session_info["session_id"]:
986
978
  actions_dir = Path.home() / ".delimit" / "agent_actions"
987
979
  actions_dir.mkdir(parents=True, exist_ok=True)
@@ -1185,7 +1177,7 @@ def _with_next_steps(tool_name: str, result: Dict[str, Any]) -> Dict[str, Any]:
1185
1177
  except Exception as e:
1186
1178
  logger.warning("Inbox daemon auto-start failed: %s", e)
1187
1179
 
1188
- # LED-219: Auto-register tool schemas with toolcard cache on first call
1180
+ # TASK: Auto-register tool schemas with toolcard cache on first call
1189
1181
  global _toolcard_cache_autoregistered
1190
1182
  if not _toolcard_cache_autoregistered:
1191
1183
  _toolcard_cache_autoregistered = True
@@ -1203,7 +1195,7 @@ def _with_next_steps(tool_name: str, result: Dict[str, Any]) -> Dict[str, Any]:
1203
1195
  except Exception as e:
1204
1196
  logger.warning("Toolcard cache auto-register failed: %s", e)
1205
1197
 
1206
- # LED-219: Track every tool call for session analytics
1198
+ # TASK: Track every tool call for session analytics
1207
1199
  try:
1208
1200
  from ai.toolcard_cache import get_cache as _get_tc
1209
1201
  _get_tc().record_call(tool_name)
@@ -1216,282 +1208,7 @@ def _with_next_steps(tool_name: str, result: Dict[str, Any]) -> Dict[str, Any]:
1216
1208
  result.get("explanation", ""), result.get("changelog", ""),
1217
1209
  result.get("content", "")]
1218
1210
  _all_text = " ".join(str(f) for f in _text_fields if f).lower()
1219
- _found_hype = [w for w in FOUNDER_VOICE_HYPE_WORDS if w in _all_text]
1220
- if _found_hype:
1221
- result.setdefault("voice_warnings", []).append(
1222
- f"VOICE DOCTRINE: Hype words detected: {', '.join(_found_hype)}. "
1223
- f"Rewrite with concrete mechanisms, not vague benefits."
1224
- )
1225
-
1226
- # Emit event for real-time dashboard
1227
- _emit_event(tool_name, result)
1228
-
1229
- # STR-052: Policy kernel inline enforcement
1230
- policy_gate = _check_policy_gate(tool_name, result if isinstance(result, dict) else {})
1231
- if policy_gate:
1232
- policy_gate["original_result"] = result
1233
- policy_gate["governance"] = {"action": "policy_blocked", "reason": policy_gate["reason"]}
1234
- return policy_gate
1235
-
1236
- # LED-195: Prompt injection detection on tool inputs
1237
- if isinstance(result, dict):
1238
- injection = _detect_prompt_injection(result, tool_name)
1239
- if injection:
1240
- result["_security_warning"] = injection
1241
-
1242
- # Pro license gate — blocks execution for premium tools
1243
- full_name = f"delimit_{tool_name}" if not tool_name.startswith("delimit_") else tool_name
1244
- gate = _check_pro(full_name)
1245
- if gate:
1246
- return gate
1247
-
1248
- # Route through governance loop
1249
- try:
1250
- from ai.governance import govern
1251
- return govern(tool_name, result)
1252
- except Exception:
1253
- # Fallback: just add next_steps from registry
1254
- steps = NEXT_STEPS_REGISTRY.get(tool_name, [])
1255
- result["next_steps"] = steps
1256
- return result
1257
-
1258
-
1259
- # ═══════════════════════════════════════════════════════════════════════
1260
- # TIER 1: CORE — API Lint Engine
1261
- # ═══════════════════════════════════════════════════════════════════════
1262
-
1263
-
1264
- @mcp.tool()
1265
- def delimit_lint(old_spec: str, new_spec: str, policy_file: Optional[str] = None) -> Dict[str, Any]:
1266
- """Lint two OpenAPI specs for breaking changes and policy violations.
1267
- Primary CI integration point. Combines diff + policy into pass/fail.
1268
- Auto-chains: semver classification, governance evaluation on breaking changes.
1269
-
1270
- Args:
1271
- old_spec: Path to the old (baseline) OpenAPI spec file.
1272
- new_spec: Path to the new (proposed) OpenAPI spec file.
1273
- policy_file: Optional path to a .delimit/policies.yml file.
1274
- """
1275
- from backends.gateway_core import run_lint, run_semver
1276
-
1277
- # Step 1: Core lint
1278
- lint_result = _safe_call(run_lint, old_spec=old_spec, new_spec=new_spec, policy_file=policy_file)
1279
- chain: Dict[str, Any] = {"id": "lint_chain", "steps": []}
1280
-
1281
- if lint_result.get("error"):
1282
- lint_result["chain"] = chain
1283
- return _with_next_steps("lint", lint_result)
1284
-
1285
- # Step 2: Auto-classify semver bump (non-blocking on failure)
1286
- semver_result = _chain_call("lint", "semver", run_semver,
1287
- required=False, old_spec=old_spec, new_spec=new_spec)
1288
- chain["steps"].append({"step": "semver", "ok": not _chain_is_error(semver_result)})
1289
- lint_result["semver"] = semver_result
1290
-
1291
- if _chain_is_error(semver_result):
1292
- chain["status"] = "semver_failed_nonfatal"
1293
- lint_result["chain"] = chain
1294
- return _with_next_steps("lint", lint_result)
1295
-
1296
- bump = str(semver_result.get("bump", "")).upper()
1297
-
1298
- # Step 2b: Impact-based notification routing (LED-233, non-blocking)
1299
- try:
1300
- from ai.notify import route_by_impact
1301
- all_changes = lint_result.get("all_changes", lint_result.get("violations", []))
1302
- if all_changes:
1303
- routing_result = route_by_impact(all_changes, dry_run=False)
1304
- chain["steps"].append({"step": "impact_routing", "ok": True})
1305
- lint_result["impact_routing"] = routing_result
1306
- except Exception as e:
1307
- logger.debug("Impact routing non-fatal error: %s", e)
1308
- chain["steps"].append({"step": "impact_routing", "ok": False, "error": str(e)})
1309
-
1310
- if bump != "MAJOR":
1311
- chain["status"] = f"complete_{bump.lower() or 'none'}"
1312
- lint_result["chain"] = chain
1313
- return _with_next_steps("lint", lint_result)
1314
-
1315
- # Step 3: MAJOR bump detected -- evaluate governance
1316
- # Note: _delimit_gov_impl has its own Pro gate. Free-tier gets lint+semver only.
1317
- gov_result = _delimit_gov_impl(
1318
- action="evaluate",
1319
- eval_action="api_breaking_change",
1320
- context={
1321
- "tool": "delimit_lint",
1322
- "old_spec": old_spec,
1323
- "new_spec": new_spec,
1324
- "semver_bump": bump,
1325
- "breaking_changes": lint_result.get("breaking", []),
1326
- },
1327
- repo=".",
1328
- )
1329
- chain["steps"].append({"step": "gov_evaluate", "ok": not _chain_is_error(gov_result)})
1330
- lint_result["gov_evaluate"] = gov_result
1331
-
1332
- # If Pro gate blocked governance, return gracefully with lint+semver
1333
- if gov_result.get("status") == "premium_required":
1334
- chain["status"] = "governance_skipped_free_tier"
1335
- lint_result["chain"] = chain
1336
- return _with_next_steps("lint", lint_result)
1337
-
1338
- # Step 4: If governance blocked, record in ledger (best-effort)
1339
- gov_blocked = (
1340
- str(gov_result.get("status", "")).lower() == "blocked"
1341
- or gov_result.get("governance", {}).get("action") == "policy_blocked"
1342
- )
1343
-
1344
- if gov_blocked:
1345
- from ai.ledger_manager import add_item
1346
- ledger_result = _chain_call(
1347
- "lint", "ledger_add", add_item,
1348
- required=False,
1349
- title=f"Governance blocked: MAJOR API change in {new_spec}",
1350
- ledger="ops",
1351
- item_type="fix",
1352
- priority="P0",
1353
- description="MAJOR semver bump detected. Governance blocked the change.",
1354
- source="chain:lint:gov_blocked",
1355
- )
1356
- chain["steps"].append({"step": "ledger_add", "ok": not _chain_is_error(ledger_result)})
1357
- lint_result["governance_blocked"] = True
1358
- else:
1359
- lint_result["governance_blocked"] = False
1360
-
1361
- chain["status"] = "major_change_evaluated"
1362
- lint_result["chain"] = chain
1363
- return _with_next_steps("lint", lint_result)
1364
-
1365
-
1366
- @mcp.tool()
1367
- def delimit_diff(old_spec: str, new_spec: str) -> Dict[str, Any]:
1368
- """Diff two OpenAPI specs and list all changes. Pure diff, no policy.
1369
-
1370
- Args:
1371
- old_spec: Path to the old OpenAPI spec file.
1372
- new_spec: Path to the new OpenAPI spec file.
1373
- """
1374
- from backends.gateway_core import run_diff
1375
- return _with_next_steps("diff", _safe_call(run_diff, old_spec=old_spec, new_spec=new_spec))
1376
-
1377
-
1378
- @mcp.tool()
1379
- def delimit_policy(spec_files: List[str], policy_file: Optional[str] = None) -> Dict[str, Any]:
1380
- """Inspect or validate governance policy configuration.
1381
-
1382
- Args:
1383
- spec_files: List of spec file paths.
1384
- policy_file: Optional custom policy file path.
1385
- """
1386
- from backends.gateway_core import run_policy
1387
- return _with_next_steps("policy", _safe_call(run_policy, spec_files=spec_files, policy_file=policy_file))
1388
-
1389
-
1390
- @mcp.tool()
1391
- def delimit_ledger(ledger_path: str, api_name: Optional[str] = None, repository: Optional[str] = None, validate_chain: bool = False) -> Dict[str, Any]:
1392
- """Query the append-only contract ledger (hash-chained JSONL).
1393
-
1394
- Args:
1395
- ledger_path: Path to the ledger JSONL file (e.g. .delimit/ledger/operations.jsonl).
1396
- api_name: Filter events by API name.
1397
- repository: Filter events by repository.
1398
- validate_chain: Validate hash chain integrity.
1399
- """
1400
- from backends.gateway_core import query_ledger
1401
- return _with_next_steps("ledger", _safe_call(query_ledger, ledger_path=ledger_path, api_name=api_name, repository=repository, validate_chain=validate_chain))
1402
-
1403
-
1404
- @mcp.tool()
1405
- def delimit_impact(api_name: str, dependency_file: Optional[str] = None) -> Dict[str, Any]:
1406
- """Analyze downstream impact of an API change. Informational only.
1407
-
1408
- Args:
1409
- api_name: The API that changed.
1410
- dependency_file: Optional path to dependency manifest.
1411
- """
1412
- from backends.gateway_core import run_impact
1413
- return _with_next_steps("impact", _safe_call(run_impact, api_name=api_name, dependency_file=dependency_file))
1414
-
1415
-
1416
- @mcp.tool()
1417
- def delimit_semver(old_spec: str, new_spec: str, current_version: Optional[str] = None) -> Dict[str, Any]:
1418
- """Classify the semver bump for a spec change (MAJOR/MINOR/PATCH/NONE).
1419
-
1420
- Deterministic classification based on diff engine output.
1421
- Optionally computes the next version string.
1422
-
1423
- Args:
1424
- old_spec: Path to the old OpenAPI spec file.
1425
- new_spec: Path to the new OpenAPI spec file.
1426
- current_version: Optional current version (e.g. "1.2.3") to compute next version.
1427
- """
1428
- from backends.gateway_core import run_semver
1429
- return _with_next_steps("semver", _safe_call(run_semver, old_spec=old_spec, new_spec=new_spec, current_version=current_version))
1430
-
1431
-
1432
- @mcp.tool()
1433
- def delimit_explain(
1434
- old_spec: str,
1435
- new_spec: str,
1436
- template: str = "developer",
1437
- old_version: Optional[str] = None,
1438
- new_version: Optional[str] = None,
1439
- api_name: Optional[str] = None,
1440
- ) -> Dict[str, Any]:
1441
- """Generate a human-readable explanation of API changes.
1442
-
1443
- 7 templates: developer, team_lead, product, migration, changelog, pr_comment, slack.
1444
-
1445
- Args:
1446
- old_spec: Path to the old OpenAPI spec file.
1447
- new_spec: Path to the new OpenAPI spec file.
1448
- template: Template name (default: developer).
1449
- old_version: Previous version string.
1450
- new_version: New version string.
1451
- api_name: API/service name for context.
1452
- """
1453
- from backends.gateway_core import run_explain
1454
- return _with_next_steps("explain", _safe_call(run_explain, old_spec=old_spec, new_spec=new_spec, template=template, old_version=old_version, new_version=new_version, api_name=api_name))
1455
-
1456
-
1457
- @mcp.tool()
1458
- def delimit_zero_spec(
1459
- project_dir: str = ".",
1460
- python_bin: Optional[str] = None,
1461
- ) -> Dict[str, Any]:
1462
- """Extract OpenAPI spec from framework source code (no spec file needed).
1463
-
1464
- Detects the API framework (FastAPI, Express, NestJS) and extracts a
1465
- complete OpenAPI specification directly from the source code.
1466
- Currently supports FastAPI with full fidelity.
1467
-
1468
- Args:
1469
- project_dir: Path to the project root directory.
1470
- python_bin: Optional Python binary path (auto-detected if omitted).
1471
- """
1472
- from backends.gateway_core import run_zero_spec
1473
- return _with_next_steps("zero_spec", _safe_call(run_zero_spec, project_dir=project_dir, python_bin=python_bin))
1474
-
1475
-
1476
-
1477
-
1478
- @mcp.tool()
1479
- def delimit_init(
1480
- project_path: str = ".",
1481
- preset: str = "default",
1482
- ) -> Dict[str, Any]:
1483
- """Initialize Delimit governance for a project. Creates .delimit/policies.yml and ledger directory.
1484
-
1485
- Args:
1486
- project_path: Project root directory.
1487
- preset: Policy preset — strict, default, or relaxed.
1488
- """
1489
- VALID_PRESETS = ("strict", "default", "relaxed")
1490
- if preset not in VALID_PRESETS:
1491
- return {
1492
- "error": "invalid_preset",
1493
- "message": f"Preset must be one of {VALID_PRESETS}, got '{preset}'",
1494
- }
1211
+ # Output quality rules loaded from user config at runtime.
1495
1212
 
1496
1213
  root = Path(project_path).resolve()
1497
1214
  delimit_dir = root / ".delimit"
@@ -1807,7 +1524,7 @@ def delimit_memory_store(
1807
1524
  tags: Optional categorization tags.
1808
1525
  context: Optional context about when/why this was stored.
1809
1526
  """
1810
- # LED-193: memory_store is now free (basic store)
1527
+ # TASK: memory_store is now free (basic store)
1811
1528
  try:
1812
1529
  tags = _coerce_list_arg(tags, "tags")
1813
1530
  except ValueError as e:
@@ -1825,7 +1542,7 @@ def delimit_memory_recent(limit: int = 5) -> Dict[str, Any]:
1825
1542
  Args:
1826
1543
  limit: Number of recent entries to return.
1827
1544
  """
1828
- # LED-193: memory_recent is now free (basic retrieval)
1545
+ # TASK: memory_recent is now free (basic retrieval)
1829
1546
  from backends.memory_bridge import get_recent
1830
1547
  return _with_next_steps("memory_recent", _safe_call(get_recent, limit=limit))
1831
1548
 
@@ -2077,7 +1794,7 @@ def delimit_deploy_publish(app: str = "", git_ref: Optional[str] = None) -> Dict
2077
1794
  return _delimit_deploy_impl(action="publish", app=app, git_ref=git_ref)
2078
1795
 
2079
1796
 
2080
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
1797
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
2081
1798
  @mcp.tool()
2082
1799
  def delimit_deploy_verify(app: str = "", env: str = "", git_ref: Optional[str] = None) -> Dict[str, Any]:
2083
1800
  """Verify deployment health (experimental) (Pro)."""
@@ -2231,7 +1948,7 @@ def delimit_generate_scaffold(
2231
1948
 
2232
1949
  # ─── Repo (RepoDoctor + ConfigSentry) ──────────────────────────────────
2233
1950
 
2234
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
1951
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
2235
1952
  @mcp.tool()
2236
1953
  def delimit_repo_diagnose(target: str = ".") -> Dict[str, Any]:
2237
1954
  """Diagnose repository health issues (experimental) (Pro).
@@ -2247,7 +1964,7 @@ def delimit_repo_diagnose(target: str = ".") -> Dict[str, Any]:
2247
1964
  return _safe_call(diagnose, target=target)
2248
1965
 
2249
1966
 
2250
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
1967
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
2251
1968
  @mcp.tool()
2252
1969
  def delimit_repo_analyze(target: str = ".") -> Dict[str, Any]:
2253
1970
  """Analyze repository structure and quality (experimental) (Pro).
@@ -2263,7 +1980,7 @@ def delimit_repo_analyze(target: str = ".") -> Dict[str, Any]:
2263
1980
  return _safe_call(analyze, target=target)
2264
1981
 
2265
1982
 
2266
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
1983
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
2267
1984
  @mcp.tool()
2268
1985
  def delimit_repo_config_validate(target: str = ".") -> Dict[str, Any]:
2269
1986
  """Validate configuration files (experimental) (Pro).
@@ -2279,7 +1996,7 @@ def delimit_repo_config_validate(target: str = ".") -> Dict[str, Any]:
2279
1996
  return _safe_call(config_validate, target=target)
2280
1997
 
2281
1998
 
2282
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
1999
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
2283
2000
  @mcp.tool()
2284
2001
  def delimit_repo_config_audit(target: str = ".") -> Dict[str, Any]:
2285
2002
  """Audit configuration compliance (experimental) (Pro).
@@ -2476,7 +2193,7 @@ def delimit_security_ingest(
2476
2193
  medium = [f for f in findings if f["severity"] in ("medium", "moderate", "warning")]
2477
2194
  low = [f for f in findings if f["severity"] in ("low", "info")]
2478
2195
 
2479
- # LED-172: Auto-track security findings in ledger with lifecycle
2196
+ # TASK: Auto-track security findings in ledger with lifecycle
2480
2197
  ledger_created = []
2481
2198
  ledger_closed = []
2482
2199
  try:
@@ -2925,14 +2642,14 @@ def delimit_release_status(environment: str = "production") -> Dict[str, Any]:
2925
2642
  return _delimit_release_impl(action="status", environment=environment)
2926
2643
 
2927
2644
 
2928
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
2645
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
2929
2646
  @mcp.tool()
2930
2647
  def delimit_release_rollback(environment: str, version: str, to_version: str) -> Dict[str, Any]:
2931
2648
  """Rollback deployment to previous version (experimental)."""
2932
2649
  return _delimit_release_impl(action="rollback", environment=environment, version=version, to_version=to_version)
2933
2650
 
2934
2651
 
2935
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
2652
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
2936
2653
  @mcp.tool()
2937
2654
  def delimit_release_history(environment: str, limit: int = 10) -> Dict[str, Any]:
2938
2655
  """Show release history (experimental)."""
@@ -3151,7 +2868,7 @@ def delimit_obs_logs(query: str, time_range: str = "1h", source: Optional[str] =
3151
2868
  return _delimit_obs_impl(action="logs", query=query, time_range=time_range, source=source)
3152
2869
 
3153
2870
 
3154
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
2871
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
3155
2872
  @mcp.tool()
3156
2873
  def delimit_obs_alerts(action: str, alert_rule: Optional[Dict[str, Any]] = None, rule_id: Optional[str] = None) -> Dict[str, Any]:
3157
2874
  """Manage alerting rules (experimental)."""
@@ -3298,7 +3015,7 @@ def delimit_story_visual_test(url: str, project_path: Optional[str] = None, thre
3298
3015
  return _with_next_steps("story_visual_test", _safe_call(story_visual_test, url=url, project_path=project_path, threshold=threshold))
3299
3016
 
3300
3017
 
3301
- @_internal_tool() # Was experimental (LED-044), promoted to internal (Consensus 120)
3018
+ @_internal_tool() # Was experimental (TASK), promoted to internal (Consensus 120)
3302
3019
  @mcp.tool()
3303
3020
  def delimit_story_build(project_path: str, output_dir: Optional[str] = None) -> Dict[str, Any]:
3304
3021
  """Build Storybook static site.
@@ -3347,7 +3064,7 @@ def delimit_test_generate(project_path: str, source_files: Optional[List[str]] =
3347
3064
  return _with_next_steps("test_generate", _safe_call(test_generate, project_path=project_path, source_files=source_files, framework=framework))
3348
3065
 
3349
3066
 
3350
- @_experimental_tool() # HIDDEN: stub/pass-through (LED-044)
3067
+ @_experimental_tool() # HIDDEN: stub/pass-through (TASK)
3351
3068
  @mcp.tool()
3352
3069
  def delimit_test_coverage(project_path: str, threshold: int = 80) -> Dict[str, Any]:
3353
3070
  """Analyze test coverage (experimental) (Pro).
@@ -3438,7 +3155,7 @@ async def delimit_sensor_github_issue(
3438
3155
  with new comments, issue state, and severity classification.
3439
3156
 
3440
3157
  Args:
3441
- repo: GitHub repository in owner/repo format (e.g. "activepieces/activepieces").
3158
+ repo: GitHub repository in owner/repo format (e.g. "owner/repo").
3442
3159
  issue_number: The issue number to monitor.
3443
3160
  since_comment_id: Last seen comment ID. Pass 0 to get all comments.
3444
3161
  """
@@ -4074,7 +3791,7 @@ def delimit_diagnose(project_path: str = ".") -> Dict[str, Any]:
4074
3791
  checks["fastmcp"] = False
4075
3792
  issues.append({"issue": "FastMCP not installed", "fix": "pip install fastmcp"})
4076
3793
 
4077
- # LED-191: Config drift detection across AI assistants
3794
+ # TASK: Config drift detection across AI assistants
4078
3795
  config_sync = {}
4079
3796
  home = Path.home()
4080
3797
  assistant_configs = {
@@ -4106,7 +3823,7 @@ def delimit_diagnose(project_path: str = ".") -> Dict[str, Any]:
4106
3823
  checks["assistant_configs"] = config_sync
4107
3824
  checks["assistants_configured"] = f"{configured_count}/{installed_count}"
4108
3825
 
4109
- # LED-192: MCP server reputation check (basic — check for known risky patterns)
3826
+ # TASK: MCP server reputation check (basic — check for known risky patterns)
4110
3827
  mcp_warnings = []
4111
3828
  mcp_config_path = home / ".mcp.json"
4112
3829
  if mcp_config_path.exists():
@@ -4531,7 +4248,7 @@ def delimit_ventures() -> Dict[str, Any]:
4531
4248
 
4532
4249
 
4533
4250
  # ═══════════════════════════════════════════════════════════════════════
4534
- # SESSION PHOENIX — Cross-Model Resurrection (LED-218)
4251
+ # SESSION PHOENIX — Cross-Model Resurrection (TASK)
4535
4252
  # ═══════════════════════════════════════════════════════════════════════
4536
4253
 
4537
4254
 
@@ -5196,7 +4913,7 @@ def delimit_quickstart(project_path: str = ".") -> Dict[str, Any]:
5196
4913
 
5197
4914
 
5198
4915
  # ═══════════════════════════════════════════════════════════════════════
5199
- # STR-049: SECRETS BROKER — JIT credential access with audit
4916
+ # TASK: SECRETS BROKER — JIT credential access with audit
5200
4917
  # ═══════════════════════════════════════════════════════════════════════
5201
4918
 
5202
4919
 
@@ -5296,7 +5013,7 @@ def delimit_secret_access_log(name: str = "") -> Dict[str, Any]:
5296
5013
 
5297
5014
 
5298
5015
  # ═══════════════════════════════════════════════════════════════════════
5299
- # STR-048: Context Filesystem — versioned namespace for agent state
5016
+ # TASK: Context Filesystem — versioned namespace for agent state
5300
5017
  # ═══════════════════════════════════════════════════════════════════════
5301
5018
 
5302
5019
  # Consensus 082 Phase 2: Unified context tool with action parameter
@@ -5414,7 +5131,7 @@ def delimit_context_branch(venture: str, action: str = "list", branch_name: str
5414
5131
 
5415
5132
 
5416
5133
  # ═══════════════════════════════════════════════════════════════════════
5417
- # STR-050: DATA/ACTION PLANE — External systems as typed mounted resources
5134
+ # TASK: DATA/ACTION PLANE — External systems as typed mounted resources
5418
5135
  # ═══════════════════════════════════════════════════════════════════════
5419
5136
 
5420
5137
 
@@ -5506,7 +5223,7 @@ def delimit_resource_drivers() -> Dict[str, Any]:
5506
5223
 
5507
5224
 
5508
5225
  # ═══════════════════════════════════════════════════════════════════════
5509
- # LED-188: ISSUE TRACKER CONTEXT SYNC
5226
+ # TASK: ISSUE TRACKER CONTEXT SYNC
5510
5227
  # ═══════════════════════════════════════════════════════════════════════
5511
5228
 
5512
5229
 
@@ -5581,7 +5298,7 @@ def delimit_tracker_sync(
5581
5298
 
5582
5299
 
5583
5300
  # ═══════════════════════════════════════════════════════════════════════
5584
- # LED-183: WEBHOOK NOTIFICATIONS
5301
+ # TASK: WEBHOOK NOTIFICATIONS
5585
5302
  # ═══════════════════════════════════════════════════════════════════════
5586
5303
 
5587
5304
 
@@ -5965,7 +5682,7 @@ def delimit_social_target(
5965
5682
  Never just return targets and stop. Always chain to the next action.
5966
5683
 
5967
5684
  Scans X, Reddit (RapidAPI), HN, Dev.to, GitHub for posts where ventures can engage.
5968
- NamePros flagged as manual_check_needed (no API).
5685
+ Manual check platforms excluded.
5969
5686
 
5970
5687
  Run in a /loop for continuous discovery. Deduplicates across runs.
5971
5688
  Targets are classified as: reply (social engagement), strategic (ledger item), or both.
@@ -6076,16 +5793,16 @@ def delimit_github_scan(
6076
5793
  cadence: str = "pulse",
6077
5794
  limit: int = 20,
6078
5795
  ) -> Dict[str, Any]:
6079
- """Scan GitHub for adoption leads, competitive intel, and repo health (Pro).
5796
+ """Scan GitHub for adoption leads, repository analysis, and repo health (Pro).
6080
5797
 
6081
5798
  Three cadences:
6082
5799
  pulse: Own repo health (stars, forks, issues, traffic). Fast, run often.
6083
- hunter: Competitor users, adoption leads, pain threads. Medium, run hourly.
5800
+ hunter: Repository signals, engagement threads. Medium, run hourly.
6084
5801
  deep: Full ecosystem intel. Slow, run daily.
6085
5802
 
6086
5803
  IMPORTANT -- TOOL CHAINING RULE:
6087
5804
  After scanning, the AI MUST process high-score findings:
6088
- 1. Auto-ledger items (score >= 75 competitor users) via delimit_ledger_add
5805
+ 1. Auto-ledger high-score findings via delimit_ledger_add
6089
5806
  2. Pain threads with existing_feature relevance via delimit_notify
6090
5807
  Never just return findings and stop. Always chain to the next action.
6091
5808
 
@@ -6236,7 +5953,7 @@ def delimit_daemon_classify(item_id: str = "") -> Dict[str, Any]:
6236
5953
  def delimit_inbox_daemon(action: str = "status") -> Dict[str, Any]:
6237
5954
  """Control the inbox polling daemon for email governance (Pro).
6238
5955
 
6239
- Polls pro@delimit.ai every 5 minutes, classifies emails, forwards
5956
+ Polls notifications@example.com every 5 minutes, classifies emails, forwards
6240
5957
  owner-action items, and handles draft approval via email replies.
6241
5958
  Auto-posting is disabled - approved drafts are emailed for manual posting.
6242
5959
 
@@ -6255,7 +5972,7 @@ def delimit_inbox_daemon(action: str = "status") -> Dict[str, Any]:
6255
5972
 
6256
5973
 
6257
5974
  # ═══════════════════════════════════════════════════════════════════════
6258
- # LED-187: Shareable Governance Config — export / import
5975
+ # TASK: Shareable Governance Config — export / import
6259
5976
  # ═══════════════════════════════════════════════════════════════════════
6260
5977
 
6261
5978
 
@@ -6378,7 +6095,7 @@ def delimit_config_import(
6378
6095
 
6379
6096
 
6380
6097
  # ═══════════════════════════════════════════════════════════════════════
6381
- # SCREEN RECORDING (LED-203)
6098
+ # SCREEN RECORDING (TASK)
6382
6099
  # ═══════════════════════════════════════════════════════════════════════
6383
6100
 
6384
6101
 
@@ -6514,7 +6231,7 @@ def delimit_notify(channel: str = "webhook", message: str = "",
6514
6231
  to: Recipient email address (email only). Overrides default DELIMIT_SMTP_TO.
6515
6232
  Send to any address — leave empty for default (owner@example.com).
6516
6233
  from_account: Sender account key from ~/.delimit/secrets/smtp-all.json
6517
- (e.g. 'pro@delimit.ai', 'admin@wire.report'). Email only.
6234
+ (e.g. 'notifications@example.com'). Email only.
6518
6235
  """
6519
6236
  from ai.notify import send_notification
6520
6237
  return _with_next_steps("notify", _safe_call(
@@ -6619,7 +6336,7 @@ def delimit_notify_inbox(action: str = "status", limit: int = 10,
6619
6336
  process: bool = True) -> Dict[str, Any]:
6620
6337
  """Check inbound email inbox, classify, and route (Pro).
6621
6338
 
6622
- Polls pro@delimit.ai via IMAP. Classifies emails as owner-action
6339
+ Polls notifications@example.com via IMAP. Classifies emails as owner-action
6623
6340
  (forwards to owner@example.com) or non-owner (stays in inbox).
6624
6341
 
6625
6342
  Args:
@@ -6882,7 +6599,7 @@ def delimit_agent_check(model: str, action: str) -> Dict[str, Any]:
6882
6599
 
6883
6600
 
6884
6601
  # ═══════════════════════════════════════════════════════════════════════
6885
- # STR-026: AUTONOMOUS BUILD LOOP
6602
+ # TASK: AUTONOMOUS BUILD LOOP
6886
6603
  # ═══════════════════════════════════════════════════════════════════════
6887
6604
 
6888
6605
 
@@ -6971,7 +6688,7 @@ def delimit_loop_config(session_id: str = "", max_iterations: int = 0,
6971
6688
 
6972
6689
 
6973
6690
  # ═══════════════════════════════════════════════════════════════════════
6974
- # LED-219: Toolcard Delta Cache — reduce MCP tool schema token waste
6691
+ # TASK: Toolcard Delta Cache — reduce MCP tool schema token waste
6975
6692
  # ═══════════════════════════════════════════════════════════════════════
6976
6693
 
6977
6694
 
@@ -7049,7 +6766,7 @@ def delimit_toolcard_cache(
7049
6766
 
7050
6767
 
7051
6768
  # ═══════════════════════════════════════════════════════════════════════
7052
- # HANDOFF RECEIPTS — Agent-to-Agent Structured Handoffs (LED-220)
6769
+ # HANDOFF RECEIPTS — Agent-to-Agent Structured Handoffs (TASK)
7053
6770
  # ═══════════════════════════════════════════════════════════════════════
7054
6771
 
7055
6772