Skip to main content

contract_cli/commands/
agent_info.rs

1use crate::error::Result;
2use crate::output::{print_raw, Ctx};
3
4pub fn run(_ctx: Ctx) -> Result<()> {
5    let config_path = crate::config::config_path()?.display().to_string();
6    let state_dir = crate::config::state_path()?.display().to_string();
7    let database = crate::config::db_path()?.display().to_string();
8
9    let commands: &[(&str, &str)] = &[
10        ("issuer add <slug> --name X --jurisdiction sg|uk|us|eu --address ...", "Register an issuer (your side of the contract). Shared with invoice-cli."),
11        ("issuer edit <slug> [--name --legal-name --logo --output-dir ...]", "Update issuer fields."),
12        ("issuer list | show <slug> | delete <slug>", "Manage issuers."),
13        ("clients add <slug> --name X --address ... [--legal-name --company-no --jurisdiction]", "Register a counterparty. Legal fields are used by contract party blocks."),
14        ("clients edit <slug> [...]", "Update client fields."),
15        ("clients list | show <slug> | delete <slug>", "Manage clients."),
16        ("new --kind nda|consulting|msa|sow|service --as <issuer> --client <client> [options...]", "Create a new contract from a clause pack."),
17        ("list [--kind X --status Y --as Z]", "List contracts."),
18        ("show <number>", "Show one contract + its clause list."),
19        ("contracts edit <number> [--title --effective --end --term-months ...]", "Edit DRAFT contract metadata (sent/signed are immutable)."),
20        ("render <number> [--template T --out PATH --open --draft | --final]", "Render to PDF. DRAFT watermark is implicit unless status is signed/active or --final is passed."),
21        ("mark <number> draft|sent|signed|active|expired|terminated", "Update status; auto-stamps sent_at / signed_at / terminated_at."),
22        ("sign <number> --side us|them --name 'Full Name' [--title T --date YYYY-MM-DD]", "Record one party's signature. When both sides sign, status auto-bumps to 'signed'."),
23        ("contracts clauses list <number>", "Show clauses currently attached to a contract."),
24        ("contracts clauses add <number> <slug> [--heading --body --from-file --position]", "Add a clause from the pack, or a custom one via --body / --from-file."),
25        ("contracts clauses edit <number> <slug> [--heading --body --from-file]", "Override heading / body of an attached clause."),
26        ("contracts clauses remove <number> <slug>", "Remove a clause."),
27        ("contracts clauses move <number> <slug> <position>", "Re-order a clause."),
28        ("contracts clauses reset <number>", "Reset to pack default."),
29        ("pack list", "List available kind/pack combinations."),
30        ("pack show <kind> [--pack standard]", "Show available clauses for a kind+pack."),
31        ("template list | preview <name> [--kind nda|consulting]", "List or preview templates."),
32        ("contracts duplicate <number> [--client C --as I]", "Clone a contract as a fresh draft."),
33        ("contracts delete <number> [--force]", "Delete a contract. --force allows non-draft."),
34        ("config show | path | set <key> <value>", "View / edit shared accounting config."),
35        ("agent-info | info", "This manifest."),
36        ("doctor", "Diagnose dependencies and DB."),
37        ("skill install", "Install embedded Claude/Codex/Gemini skill."),
38        ("update [--check]", "Self-update."),
39    ];
40    let mut commands_map = serde_json::Map::new();
41    for (k, v) in commands {
42        commands_map.insert(
43            (*k).into(),
44            serde_json::Value::String((*v).into()),
45        );
46    }
47    let templates = crate::typst_assets::list_templates().unwrap_or_default();
48    let packs = crate::clauses::list_packs();
49
50    let manifest = serde_json::json!({
51        "name": "contract",
52        "version": env!("CARGO_PKG_VERSION"),
53        "description": env!("CARGO_PKG_DESCRIPTION"),
54        "commands": commands_map,
55        "flags": {
56            "--json": "Force JSON envelope output (auto when piped)",
57            "--quiet": "Suppress human output",
58        },
59        "exit_codes": {
60            "0": "Success",
61            "1": "Transient error (IO, render)",
62            "2": "Config error",
63            "3": "Bad input / not found / ambiguous",
64        },
65        "envelope_schema": {
66            "version": "1",
67            "status": "success | error",
68            "data": "… (success)",
69            "error": "{ code, message, suggestion } (error)",
70        },
71        "config_path": config_path,
72        "state_dir": state_dir,
73        "database": database,
74        "templates": templates,
75        "packs": packs.into_iter().map(|(k, p)| serde_json::json!({"kind": k, "pack": p})).collect::<Vec<_>>(),
76        "kinds": ["consulting", "nda", "msa", "sow", "service"],
77        "fee_spec": "type:amount:currency — e.g. fixed:8400:SGD | hourly:200:SGD | daily:1500:SGD | retainer:5000:SGD",
78        "first_run": [
79            "contract doctor --json",
80            "contract issuer list --json     # CHECK FIRST — shared with invoice-cli",
81            "contract clients list --json    # CHECK FIRST — shared with invoice-cli",
82            "# Only if a needed issuer/client is missing, then:",
83            "contract issuer add <slug> --name <display-name> --jurisdiction sg|uk|us|eu --address \"line1\\nline2\"",
84            "contract clients add <slug> --name <client-name> --legal-name <legal> --address \"line1\\nline2\"",
85            "contract new --kind nda --as <issuer> --client <client> --purpose 'description'",
86            "contract render <number> --open",
87        ],
88        "shared_state": {
89            "database": database.clone(),
90            "shared_with": ["invoice-cli (binary: invoice)"],
91            "shared_tables": ["issuers", "clients", "number_series"],
92            "discovery_workflow": "Before creating a new issuer or client, ALWAYS run `contract issuer list --json` and `contract clients list --json` (or the invoice-cli equivalents). The accounting suite's whole point is one source of truth — duplicating entities here pollutes invoicing too. If the entity exists under a different slug, prefer using the existing slug over creating a new one.",
93            "legal_fields_on_clients": "Three columns added in V7 are contract-specific: `legal_name`, `company_no`, `legal_jurisdiction`. If an existing client (from invoice-cli) is missing them, fill via: contract clients edit <slug> --legal-name X --company-no Y --jurisdiction Z."
94        },
95        "examples": [
96            { "goal": "Quick mutual NDA",
97              "command": "contract new --kind nda --as acme --client meridian --purpose 'evaluation of a joint product' --term-years 3" },
98            { "goal": "Consulting agreement with fixed fee",
99              "command": "contract new --kind consulting --as acme --client meridian --purpose 'design a dashboard' --fee fixed:8400:SGD --term-months 3 --deliverable 'Design' --deliverable 'Build'" },
100            { "goal": "Render with no watermark",
101              "command": "contract render NDA-acme-2026-0001 --final --open" },
102            { "goal": "Record both signatures",
103              "command": "contract sign NDA-acme-2026-0001 --side us --name 'B. Djordjevic' --title CEO; contract sign NDA-acme-2026-0001 --side them --name 'Sophie Lin' --title 'Head of Marketing'" },
104        ],
105        "guardrails": [
106            "BEFORE creating any issuer or client, run `contract issuer list` and `contract clients list` — the DB is shared with invoice-cli; duplicates pollute both tools.",
107            "Run doctor before first use.",
108            "Use --json for agents; stdout is data, stderr is diagnostics.",
109            "Drafts render with a DRAFT watermark by default. Use --final to suppress before sending out for signature.",
110            "Once a contract is sent/signed, only the status / signature columns can change.",
111            "These clauses are practical plain-English starting points, not legal advice. Have a lawyer review for material engagements.",
112        ],
113    });
114    print_raw(&manifest);
115    Ok(())
116}