tasks/workstreams/mcp-analyst-agent/initiatives/dashboard-linking/spec.md

Spec

Goals (v1)

  1. Authors can link between boards without hand-building environment-specific absolute URLs—works for dft serve and Cloud after resolution.
  2. Query parameters on those links align with existing dashboard variables (see Cloud dashboard_render query parsing).
  3. Authoring uses standard Markdown link URLs only—no custom markdown dialect. Optional .md / .yaml / .yml suffixes on paths may be stripped as author sugar (tool behavior, not CommonMark).

Non-goals (v1)

Dependencies


Author-facing URL model (v1)

Dashboard URL root (author view): paths are root-relative from the logical dashboard namespace—authors do not type a storage prefix like faces/.

Examples:

{% raw %}

[Open tickets](/zendesk/tickets/list?status=open)
[Ticket detail](/zendesk/tickets/detail?id={{ ticket_id }})

{% endraw %}

Implementation mapping: the resolver maps author path → canonical project slug used by Cloud and dft serve today (typically under faces/ on disk, e.g. faces/zendesk/tickets/list). Exact normalization rules must match dashboard discovery / existing slug behavior—see open questions.

Relative paths: ../ and ./ resolve against the current board’s slug directory (after the same author-root ↔ storage-slug mapping), then rewrite for Cloud vs serve—see ADR-001.

Convention for “views” (no metadata): teams can standardize recognizable paths such as:

This is documentation + habit, not enforced schema in v1.


Why render-time rewriting?

Concern Compile time Render time
Knows Cloud org/project No Yes (dashboard_render)
Same YAML in CLI and Cloud Yes Yes

Browsers resolve relative href against the HTML page URL (Suite: /{org}/{project}/d/{slug}/), not the repo slug tree—so we rewrite board links when rendering. Same pattern as static site generators that “fix” .md links: tool behavior, not CommonMark.


Resolution targets (after rewrite)

Runtime Shape (conceptual)
dft serve /{storage_slug_path}?{query} per dataface/core/serve/server.py
Cloud /{org}/{project}/d/{dashboard_slug}/?{query} + merge branch (allowlist TBD) from current request when absent on link

Pass link_context through render(..., **options) into the content pipeline (dataface/core/render/faces.py, etc.); centralize in e.g. dataface/core/render/board_links.py with tests.


Phase plan (v1)

Phase Scope
1a Root-relative /… + board-relative ../ / ./ in face.content; suffix strip; serve + Cloud
1b Context merge (branch, allowlist)
2 Optional escape hatch only if ambiguity appears (e.g. explicit scheme)—not default

M5 (separate task): optional canonical_for / entity index only if product proves need beyond conventions—task.


Testing & docs


Open questions

  1. Allowlist for merged query params (branch only vs more).
  2. Board links in nested includes / chart footnotes—same pipeline if shared.
  3. Author path → storage slug when both faces/ and dashboards/ trees exist (precedence, explicit disambiguation).