# Rogo implementation guide: MuniPro banker skills

Status: Active
Skill package and client-result schema: version 1.

This guide defines five portable workflows over MuniPro's existing eleven-tool
banker profile. It does not assume a Rogo-specific SDK, skill-import endpoint,
citation API, browser callback or renderer. Rogo supplies those host bindings.
Packaging/source verification is separate from deployment and actual Rogo
acceptance. The release handoff records the candidate/source hash and which
client tests have actually passed.

## Start here

1. Configure the existing custom MCP connector for `https://munipro.com/mcp`.
   Use [OAuth and client setup](https://munipro.com/static/mcp/rogo-connection-guide.md).
   Valid MuniPro logins do not require hostname preapproval; normal account,
   tenant, role, scope, entitlement and borrower checks still apply. Complete
   the real callback registration and user consent with S256 PKCE. A native
   loopback callback and a web HTTPS callback have different transport rules.
2. Request the approved banker scopes. `debt.read` serves data and banker jobs;
   `borrowers.request` is needed for coverage requests. The documented setup
   also requests `catalog.read` and `offline_access`; omit the write scope for
   read-only use. Scopes cannot enlarge the profile. Keep token handling inside
   the connector, including refresh and revocation.
3. Complete MCP initialization with the host SDK's negotiated protocol. Follow
   all `tools/list` cursors and enforce that every discovered name belongs to
   the published [banker profile](https://munipro.com/static/mcp/banker-tool-profile.json),
   with a maximum of eleven. Fewer tools can be legitimate; identify the missing
   capability instead of calling an absent broader-catalog tool.
4. Install/load the workflow instructions as described below. Start a request
   with `get_current_munipro_context({"detail":"summary"})`, choose the relevant
   skill, and load only that skill's detailed instructions.
5. Run the joint acceptance cases before claiming client compatibility. Begin
   with a read-only debt brief, then file retrieval, then human-approved coverage.

## Package and discovery

`banker-skills.json` is a small machine-readable catalog. Each entry identifies
its skill, purpose, declared tool dependencies, host requirements, public
instruction URL and the exact existing MCP navigation call to load it.

| Skill ID | Requested outcome |
|---|---|
| `create-cited-debt-brief` | Debt/debt-service/callable analysis with reconciled tables and citations. |
| `assemble-issuer-source-pack` | Retrieved JSON, uploaded workbooks/DDL and indexed statement PDFs, plus an integrity/coverage manifest. |
| `prepare-borrower-coverage` | Verified borrower lookup/roster or a requested verification preview for human approval. |
| `create-banker-presentation` | A firm-template issuer deck or a reusable reference template with named data bindings. |
| `tie-out-banker-deliverable` | A read-only check of a MuniPro-built brief, pack or deck against MuniPro records: figures, identities and sources only, not writing or design. Never edits it. |

**Native MuniPro assistant:** the banker context's `banker_skills` field holds
only discovery metadata. Execute the selected entry's `read_instructions` call,
for example:

```json
{"name":"get_munipro_navigation","arguments":{"area":"banker-skill:create-cited-debt-brief"}}
```

The result is instruction metadata with `instructions_only: true` and
`skill.instructions_markdown` in the navigation application payload. It does
not execute the workflow or grant access. This uses the existing tool and
input schema; it adds no MCP tool or OAuth scope. The legacy context full-detail
presentation payload remains available for existing clients.

**Rogo:** use the same on-demand navigation call, or register the selected
compiled `skills/<id>/SKILL.md` as a reusable host workflow. Rogo is MuniPro's
closest integration partner, and every MuniPro skill is offered on Rogo. The
downloadable bundle is a transport package containing a standalone skill
directory for every one of them: the five above; the municipal research skills
issuer-credit-profile, new-issue-comparables, bondholder-targeting,
debt-service-coverage-history and bond-document-summary, which run alongside
Rogo's own research skills; the municipal job skills
financing-opportunity-analysis, trading-data-analysis, rating-agency-presentation
and rfp-response; and the issuer skills budget-book-debt-service and
acfr-debt-notes. Skills beyond the five depend on tools beyond the eleven-tool
profile and load through `profile-skill:<id>` navigation; each works only when
the connection's live tools hold its dependencies. The bundle also holds the
helper script, references, schemas, examples and a SHA-256 manifest. The bundle
is not an assertion that Rogo accepts a multi-skill ZIP upload. If Rogo requires
its own workflow configuration, copy the relevant instruction body and map the
ports below. Keep shared material available on demand rather than injecting
every workflow and all sixteen slide recipes into every prompt.

**Codex/Claude:** the common `SKILL.md` instruction format can be reused with
the host's supported installation method. Install each standalone directory
or use the existing MuniPro plugin source. Connect the same MCP server separately
when the installation method does not include connector configuration.
[OpenAI skills](https://developers.openai.com/plugins/concepts/skills) and
[Claude skills](https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview)
describe host packaging; no automatic cross-product installation is implied.

## Host capabilities Rogo must bind

| Port | Required behavior | When unavailable |
|---|---|---|
| MCP execution | Initialized authenticated session, cursor-aware discovery and typed tool calls; preserve actual structured/text/error envelopes. | Block the dependent operation; do not fall back to unrelated REST credentials. |
| Async scheduler | Poll exact owned job references with backoff/cancellation and inspect terminal job/application outcomes. | Report pending/partial; never treat queued work as complete. |
| Artifact HTTP | Exact-origin bearer GET, token refresh, no credential forwarding on redirects, byte streaming and integrity capture. | A file inventory is partial; do not claim retrieved files. |
| Source registration | Register URL/title/excerpt/record identity through Rogo's supported citation mechanism and observe its rendering. | Return ordinary links labeled `link_only`; native acceptance remains pending. |
| Human review link | Show the returned approval link so the same person can sign in and explicitly approve in MuniPro. | Leave the request `awaiting_approval`; never automate the approval form. |
| Local artifacts | Store permitted files, calculate/check hashes and expose retrievable output files to the user. | Deliver supported inline data or a clearly partial inventory. |
| Firm deck/editor/renderer | Read an authorized template, bind editable objects where supported and render/inspect every slide. | Return a binding/data packet, not a claimed finished presentation. |

These ports are responsibilities, not proposed Rogo endpoint names. A skill
file alone does not implement OAuth, source registration or browser/file UX.

The catalog's `host_capabilities` values are planning labels for these ports,
not an API or an access grant, and MuniPro does not check them.
`structured_tool_results` is MCP execution. `authenticated_munipro_downloads`
is Artifact HTTP, with the async scheduler for dataset jobs. `async_job_polling`
is the async scheduler for a skill's own job calls. `artifact_storage`
is Local artifacts. `human_browser_approval` is the Human review link.
`authorized_firm_template` and `presentation_rendering` are the Firm
deck/editor/renderer. The catalog has no separate source-registration key. For
each citation, record native_registered only when the host's registration and
rendering were observed; otherwise use link_only or pending as appropriate.
Joint Rogo acceptance is a separate status. Every catalog entry carries
`host_capabilities`. The catalog's `tool_count_ceiling` is the eleven-tool
banker profile's ceiling and covers the `banker-skill:` entries only;
`profile-skill:` entries list their own dependencies under `tools`.

## Tool and HTTP mapping

Six business tools supply the initial scope. Five support tools provide context,
navigation, `fetch`, job status and cancellation. For exact request/response
schemas use the bundled/public profile JSON. MCP IDs are normally strings;
HTTP path IDs are positive integers. `issuer_id` is Borrower ID.

| Workflow operation | MCP | Dedicated banker HTTP equivalent |
|---|---|---|
| Resolve permitted borrowers | `list_verified_borrowers` | GET `borrowers/` with documented filters/pagination. |
| Prepare coverage | `request_borrower_verification` | POST `verification-requests/` with name/state and optional prefix/category. |
| Obtain debt datasets | `get_debt_details_dataset` | POST `issuers/{issuer_id}/datasets/`. |
| List current uploads | `list_issuer_files` | GET `issuers/{issuer_id}/files/`. |
| Download one upload | `get_issuer_file_download`, then authorized GET | GET `issuers/{issuer_id}/files/{file_id}/`. |
| List statement PDFs | `list_issuer_debt_documents` | GET `issuers/{issuer_id}/documents/`; follow `next_offset`. |
| Download indexed PDF | No dedicated MCP download tool; follow the listed row's `download_url` | GET `issuers/{issuer_id}/documents/{signed_locator}/`. |
| Poll dataset job | `get_job_status` | GET `jobs/{job_uuid}/`. |
| Download dataset JSON | No dedicated MCP download tool; follow the completed job's `api_download.url` for original bytes | GET `datasets/{signed_locator}/`. |

HTTP base: `https://munipro.com/api/assistant/v1/banker/`. Preserve trailing
slashes and signed locators. There is no dedicated HTTP counterpart here for
MCP result-page `fetch`, skill navigation or cancellation. The browser's XHR
builders and older API families are not interchangeable bearer endpoints.
See [API route reference](https://munipro.com/static/mcp/api-route-reference.md)
and [banker integration](https://munipro.com/static/mcp/banker-integration-guide.md).

MCP's `structuredContent.result` is not a universal direct-HTTP JSON path.
Each HTTP route has its own documented body. The file list has no `status`
field. HTTP/MCP success, job success and a complete retrieved artifact are
separate observations. The skill-result schema below is client-created.

## Workflow implementation

### Debt brief

Resolve identity; capture as-of/fiscal-year/selection assumptions; request only
the needed datasets; complete the async and artifact flow; construct tables at
one grain; reconcile totals; register citations; deliver the brief and source
appendix. The selected instruction includes its analysis contract.

The datasets are the debtDetails builders' outputs, not HTML scraping or a new
cashflow model. Fields, graph identities, chart prefixes, aggregation rules,
variable overlays and unsupported data are in the bundled
`references/banker-data-guide.md`. Preserve returned warnings and notices.
`securityIds` narrow calculations, not automatically the outstanding display
rows. Filter issuer-wide outstanding leaves explicitly when comparing a
selected-security calculation. Do not repeat that issuer-wide sum per partition.

### Source pack

Inventory the requested categories, page every list, retrieve actual bytes,
record source identity/availability, and verify the local manifest. The
`assemble-issuer-source-pack` directory includes a Python standard-library
verifier. Run it only on the downloaded local pack:

```text
python skills/assemble-issuer-source-pack/scripts/verify_source_pack.py manifest.json --root path-to-pack
```

It performs no network requests and accepts no token. It checks contained paths,
sizes and hashes; it does not prove document relevance or discovery completeness.
Its zero exit status means the manifest is internally valid; inspect `complete`
and coverage notes separately. Its helper contract distinguishes independent
MuniPro response digests from hashes calculated only after local retrieval.

Use the three download contracts independently. Indexed PDFs use the returned
MuniPro bearer locator and may supply a SHA-256 `ETag`; re-list after 410.
Dataset exports expose their artifact integrity metadata. Uploaded files do
not inherit a PDF locator lifetime or server-digest promise.

### Borrower coverage

Search the permitted verified roster. For a user-requested missing borrower,
prepare the request with name/state and optional CUSIP prefix/category. Preserve
the returned pending-operation ID and approval link. Display the link; the same
person approves the stored company-bound request in MuniPro. The HTTP preview
can intentionally be 400/`approval_required`. Do not collapse it into a generic
validation failure or automatically retry it.

There is no approval-status polling tool or Rogo callback contract in this
profile. Browser confirmation and API receipt consumption are distinct evidence.
Even a committed `requested` or `already_requested` result means staff review,
with `borrower_verified: false`. It does not verify or publish debt.

### Firm presentation/template

Choose reusable-template or issuer-deck mode. Preserve an authorized firm master,
layouts, fonts, logos and required disclosures in a new copy. Bind named slots
to exact datasets/filters and keep the template reference/hash plus per-slide
source, reconciliation and render evidence. The selected instruction includes
the binding contract and all sixteen recipes.

The initial profile supplies the first four recipes: outstanding by credit,
debt service by credit, callable by credit and callable by coupon. A complete
liquidity wall needs additional facility evidence. The other recipes require
their separately authorized market, modeling or other sources. Do not expose
broader tools, fabricate sample data, or imply the recipe grants access.

## Result pages, downloads and recovery

Use the shared banker protocol embedded in each compiled skill. On a paged
done result, apply the `s000` root initializer before section operations,
follow required provenance/notice companions and compare outcome copies.
Traverse every required global page for a complete artifact or root object
group; targeted section fetches can answer a bounded question but are not a
complete export. HTTP-only adapters cannot fetch these pages through the nine
banker routes. Use MCP `fetch`, or request a smaller result.

Attach the current bearer only after parsing and verifying the exact origin
`https://munipro.com`. Keep the signed URL intact and reject credential-bearing
redirect forwarding. Never send the bearer to EMMA. MuniPro's server uses its
established aiohttp proxy/cache for those PDFs; no new direct EMMA client is
needed in a skill or Rogo adapter.

| Condition | Adapter response |
|---|---|
| MCP/authentication failure | Preserve the layer/reason; refresh or reauthorize through the connector when appropriate. No silent account substitution. |
| Access/scope/tier refusal | Stop that operation and explain the current access limitation. A skill is not a permission grant. |
| Queue/running | Schedule a later bounded poll of that exact job. |
| Failed/cancelled job | Stop; retain the truthful failure/result outcome. |
| 410 expired locator | Re-list PDF metadata or obtain a fresh authorized dataset job/locator as appropriate. |
| Large dense selection refused | Narrow or partition explicitly with disjoint security IDs and consistent assumptions. Never truncate silently. |
| Empty non-CUSIP document index | Report incomplete indexing; preserve debt and inspect permitted uploaded files. |
| Approval-required preview | Present the browser review link and remain awaiting approval. |
| File or rendering port unavailable | Deliver a partial result describing the missing capability. |

OAuth refusal reasons use `error_description`; MCP principal refusal reasons
use `error`. Inspect the actual endpoint schema. Do not create a universal
error-field parser that loses those distinctions.

## Citations and non-CUSIP identity

Use the exact absolute `citation.url` with `?view=canonical`. Readers use their
MuniPro browser session and may be asked to sign in; MCP OAuth does not sign
the browser in. Current record links are not frozen historical evidence, so
retain dated export bytes and hashes.

`citations[].url` is reserved for the canonical MuniPro record URL. Keep a
public EMMA `source_url` in the source-pack manifest, not in `citations`. Never
put a bearer or a signed download locator in either place.

For series-level audit, pair the issuer URL with returned designation,
`issue_id`/`series_id`, and source/workspace identity. There is no series-row
permalink. Use `(issuer_id, security_id)` for bonds regardless of whether a
CUSIP exists. Identical blank identifiers/coupons/maturities do not justify
deduplication. Missing CUSIP indexing is a source-coverage limitation, not
absence of debt or legal documentation.

Rogo supplies the native citation-registration binding. Register or retain a
source title, canonical URL, precise record IDs, excerpt where appropriate,
and export reference/hash. Any additional source key is a client-created key,
not a new MuniPro record ID. Record citation mode as `native_registered`,
`link_only` or `pending`. Only observed registration supports the first value.

## Client-created output contract

`schemas/skill-result.schema.json` defines a common Rogo/host handoff envelope.
It does not change MCP or HTTP responses. The adapter populates it after
observing the actual operations. The skill `status` describes the requested
work product, not global integration acceptance.

Use `complete`, `partial`, `needs_input`, `awaiting_approval`, `blocked` or
`failed`. Preserve source citations, artifacts, limitations, notices and
as-of parameters. Never place tokens or signed download locators in the result.
Use `examples/debt-brief-result.json` as a synthetic shape example, not evidence
that its IDs or numbers came from production.

## Joint acceptance and release evidence

`acceptance-cases.json` defines review cases and required observations. Rogo
should record client/version/workspace, date, skill/package hash, profile/tool
names, redacted call IDs, outcome, actual artifacts and the reviewer. Retain
actor/company identity only according to the partner's approved audit policy.
Never retain bearer/refresh tokens or confidential raw authorization logs.

Required cases cover: eleven-tool discovery; mixed CUSIP/non-CUSIP debt without
double counting; selected-security versus issuer-wide scope; multi-page results;
all three authenticated download types; expiry and denied access; native source
registration versus links; approval-required HTTP 400; actual human submission;
firm-template rendering; and missing sources/capabilities.

Source checks, synthetic/offline helper tests, CI, protected landing, production
publication, account admission, actual Rogo OAuth and each joint case are
separate evidence scopes. Mark unperformed cases pending. Rogo's joint tests
do not circularly block sending the instructions needed to perform them.
The final document/email edition still receives Astra and Fable review before
handoff to James. Never describe a prepared package as installed or accepted.
