Implementation Layer
CTH Business Objects
CTH Business Objects
The discrete entities the CTH agentic workflows operate on.
Post
Field: caption, image_path, country, milestone, platforms, supporters.
Image
Generated by Ideogram. Must be >=1080x1080, JPG or PNG, brand-compliant.
Country audience
Target audience per country (CO, PE, SV, GT, CR). Drives copy + supporter set.
Milestone
Campaign milestone (launch, midpoint, deadline, winners, bootcamp).
Supporter
Organisation credited in a post -- varies per country.
Workflow Run
A single execution of a workflow. Has run_id, eval_score, status, audit URL.
TODO: expand with worked examples per object.
Opportunity (Grants)
Funder, call/RFP, deadline, budget ceiling + currency, CTH role (lead / co-applicant / implementing / subcontractor), required partners, funder type (multilateral / bilateral / climate-innovation / philanthropic / corporate / bid-cp).
Fit Scorecard (Grants)
The 9 weighted criteria from cth-grant section 1a. Produces a 0-45 score + GO / CONDITIONAL / NO-GO verdict.
Scope Brief (Grants)
In/out of scope, dependencies. Activities sized to budget (3-5 for <50K EUR, 8-12 for >150K EUR).
Theory of Change (Grants)
Master ToC adapted to funder type and language register per section 3b.
Budget (Grants)
The section 5b structure. Carries salary_pct, overhead_pct, cofinance_pct, total. Hard gate: salary must be 40 percent or less.
Narrative (Grants)
Universal narrative sections per section 4b: exec summary, context, methodology, results, org capacity, budget summary, annexes.
Pre-Submission Checklist (Grants)
13-line checklist (section 4d). Each line: yes / no / waived-by-Gideon. All must be YES or waived before submission.
Submission (Grants)
Record of final package + human-performed submission + reporting schedule. The pod never auto-submits.
Authority Matrix
Authority Matrix
| Action | Tier | Requires HITL? | Notes |
|---|---|---|---|
| notion.read | read | No | scoped to CLP26 DB |
| bookstack.read | read | No | |
| ideogram.generate | write_reversible | No | spend-capped |
| notion.create_draft | write_reversible | No | |
| monday.create_item | write_reversible | No | |
| buffer.publish | write_irreversible | Yes | first 20 always HITL |
| gmail.send | write_irreversible | Yes | |
| davivienda.submit | write_irreversible | Yes | Gideon only |
TODO: keep aligned with
/opt/cth/client_authority.yaml.
Grants Pipeline Actions
| Action | Tier | Requires HITL? | Approver | Notes |
|---|---|---|---|---|
| monday.read_opportunities | read | No | -- | scan board |
| fit_score.compute | read | No | -- | auto + partial |
| scope_toc.generate | write_reversible | No | -- | |
| budget.build | write_reversible | No | -- | |
| narrative.draft | write_reversible | No | -- | |
| go_no_go.decide | write_reversible | Yes if conditional | Gideon | auto GO if >=35, auto NO-GO if <25 |
| budget.review | write_reversible | Yes on red flags | Delegate | blocking if salary >40 pct |
| pre_submission.approve | write_irreversible | Always | Delegate | every submission |
| submission.perform | write_irreversible | Always | Human manual | pod stops at ready_to_submit |
CLP26 Runbook
CLP26 Runbook
How to operate the CLP26 workflow.
Triggering a run
The systemd timer fires every 15 minutes. To force a run:
sudo systemctl start cth-runner@clp26.service
Approving HITL
You will see a Telegram message in #hitl-approvals with Approve / Reject buttons. Tap one. Decision logged automatically.
Inspecting a run
- Monday board
CLP26 Workflow Runs journalctl -u cth-runner@clp26.service -n 200jq 'select(.workflow_run_id=="<id>")' /opt/cth/audit.jsonl
Pausing the workflow
sudo systemctl stop cth-runner-clp26.timer
TODO: add screenshots after first run.
Recovery Playbook
Recovery Playbook
Eval below threshold
HITL prompt fires automatically. Reject + add reason -> run terminates, recovery row on Monday.
Buffer publish failure
Automatic retry 3x (exponential). If still failing, alert in #recovery. Manual options:
- Reschedule for later
- Post a correction
- Mark as cancelled
Orphan run
runner.py detects stale state.json lock (>1h old) on next tick -> logs orphan, alerts.
Image generation failure
Run marked failed with image_unavailable. Re-run from Step 03 manually.
Wrong-country copy
Triggers country_copy_check failure -> HITL -> reject -> re-draft.
TODO: add SOP for each failure mode after W6 simulation pass.
Grants Pipeline Failure Modes
Budget blocking gate fires -- salary above 40 pct
The 40 pct salary check is a hard gate. When fired:
- Run is blocked and cannot reach pre-submission
- Telegram alert in hitl-approvals with restructuring guidance
- Options: restructure budget and re-run, or waive with explicit override
Partner unresponsive -- more than 14 days
Automatically flagged during scan. Partner status downgraded to unresponsive. Alert in agent-ops. Consider replacing partner or dropping consortium component.
Capacity guard -- 2 or more active drafts
New evaluating opportunities are deferred until an active draft completes. Logged as capacity_deferred in audit. No intervention needed; next tick retries.
HITL gate timeout
If no response within timeout: run terminates cleanly. Opportunity stays at current stage. Next daily tick retries.
Eval score below threshold
Routes through pre-submission HITL with the score and failing checks visible. Reviewer can approve despite low score.
Subagent verify unavailable
Graceful degradation: check returns passed=True with weight=0 so it does not count. Other checks still score normally.
Grants Runbook
Grants Pipeline Runbook
Operator guide for the CTH Grants Pipeline -- a deadline-watcher state machine with 3 HITL gates.
Architecture
The grants pipeline runs daily at 08:00 America/Bogota (13:00 UTC) via systemd timer. It scans the Grants Opportunities Monday board for actionable rows and advances each opportunity through an 8-step state machine.
Key principle: The pod NEVER auto-submits. It produces a ready-to-submit package; a human performs the final submission.
State Machine
evaluating -> fit_score -> go_no_go HITL1 -> scoping -> budgeting HITL2
-> drafting -> eval -> awaiting_HITL HITL3 -> ready_to_submit -> human submits
Terminal states: submitted, won, lost, no_go.
HITL Gates
Gate 1 -- GO / NO-GO (step 03)
- Approver: Gideon
- Auto GO: fit score >= 35/45
- Auto NO-GO: fit score < 25/45
- Conditional 25-34: requires explicit approval via Telegram inline keyboard
- Timeout: 30 minutes, run terminates cleanly, retries next tick
Gate 2 -- Budget Review (step 05)
- Approver: Delegate
- Blocking gate: salary > 40 pct, run blocked until restructured or waived
- Red flags: overhead > cap, missing M&E line, routes to HITL for review
- Budget restructuring guidance provided in Telegram message
Gate 3 -- Pre-Submission (step 07)
- Approver: Delegate
- Every pre-submission checklist line must be YES or explicitly waived
- Posts assembled package links + 24h deadline buffer reminder
- On approval: stage = ready_to_submit, pod STOPS
How to Submit (Human)
After the pod marks an opportunity as ready_to_submit:
- Review the package links posted in agent-ops
- Verify all checklist items in the Grants HITL Approvals board
- Submit via the funder portal or email as specified
- Update the Grants Opportunities board: stage to submitted
- Record submission details in Monday
Manual Trigger
sudo systemctl start cth-runner@grants.service
Logs
sudo journalctl -u cth-runner@grants.service -f
Monday Boards
- Grants Opportunities: 18414094447 -- source/state board
- Grants Workflow Runs: 18414094534 -- per-tick run state
- Grants HITL Approvals: 18414094587 -- approval records
- Grants Audit Log: 18414094632 -- forensic trail for Advisory Board
- Grants Recovery Actions: 18414094675 -- failure tracking
Planning Horizon
- Scan: 90 days before deadline, opportunities appear on radar
- Action required: 45 days before deadline, must be actively progressing
- Capacity guard: max 2 active drafts simultaneously