Spaces:
Running
Running
|
Download docs/agentspot_task_manager_agent.md from thoughtspot-demoprep/mcp: direct link, hf CLI and curl.
- Browser
- Download file 22.7 kB
-
https://huggingface.co/spaces/thoughtspot-demoprep/mcp/resolve/main/docs/agentspot_task_manager_agent.md
- Command line
-
hf download hf://spaces/thoughtspot-demoprep/mcp/docs/agentspot_task_manager_agent.md
-
curl -L -o agentspot_task_manager_agent.md https://huggingface.co/spaces/thoughtspot-demoprep/mcp/resolve/main/docs/agentspot_task_manager_agent.md
22.7 kB
| # AgentSpot agent: Task Manager, on the team tracker | |
| *Design and paste-ready agent definition. Written 2026-10-20 from boone's brief and his answers (Supabase store, server-side GitHub, two repos, ThoughtSpot views). Code on branch `feature/tracker`; status in `sprint_2026_04.md`.* | |
| *The agent is built in the AgentSpot UI on secloud. The tracker is code in this repo: `demoprep_app/tracker/` (schema, store, GitHub sync, TML) and six tools in `mcp_server.py`.* | |
| Team: Mike (mike.boone), Jack (jack.rayner), Manny (mani.uppala), Gora (gora.sudindranath). Overall view also for Paul. | |
| --- | |
| ## The brief | |
| Pull requests already go through GitHub, but nothing else does. Sprint notes are markdown | |
| files in this repo and "ping Jack" happens in Slack by hand. Wanted: | |
| - one task list the team can assign to each other, kept in Supabase; | |
| - pull requests understood by the tracker: which task a PR belongs to, what state it is in; | |
| - a personal view (my stuff) for each person, and an overall view for a manager; | |
| - a way to hand work to an agent, through Slack or the database. | |
| --- | |
| ## Decisions | |
| | Item | Decision | Source | | |
| |---|---|---| | |
| | Task store | Four tables in the existing Supabase project beside `demo_history`: `tasks`, `task_notes`, `pull_requests`, `tracker_people`, plus the `task_board` view for ThoughtSpot. Real tables, not the `demo_history` status-sentinel pattern, because ThoughtSpot needs typed columns. `demoprep_app/tracker/schema.sql`. | boone (Supabase); shape recommended | | |
| | Who writes | Six tools on the DemoPrep MCP server: `list_tasks`, `create_task`, `update_task`, `add_task_note`, `list_pull_requests`, `sync_pull_requests`. The AgentSpot agent, the Slack bot, and any Claude Code session with the connector use the same tools. | recommended | | |
| | Pull requests | The MCP server polls GitHub with a repo-scoped token every 10 minutes (`demoprep_app/tracker/github_sync.py`). A PR links to a task by a stored link, by the task's own `pr_url`, or by `T-<id>` in its title, body or branch name. A merge adds a note to the task; it never closes it. | boone (server-side token) | | |
| | Repos | `boone10/DemoPrep` and `thoughtspot/tse_demos`, set by `TRACKER_REPOS`. | boone | | |
| | Views | ThoughtSpot on secloud with a live PostgreSQL connection to Supabase (ThoughtSpot Cloud lists PostgreSQL as a supported connection; no Snowflake mirror). Model `Team Tracker` and a Liveboard with Team, Pull requests and Stale tabs: `demoprep_app/tracker/tml/`. Personal view by an Owner Name filter saved as each person's personalized view, or a one-line RLS rule. An AgentSpot App can be generated from the same model later. | boone (ThoughtSpot) | | |
| | Identity | `owner` and `requester` are ThoughtSpot usernames (`mike.boone`), what `ts_username` sees in RLS and what the run reports print. The agent passes the caller's name; the store resolves username, email, GitHub login, display name or first name, and refuses anything else. | default | | |
| | Communication | AgentSpot's Slack bot bound to one public channel; a scheduled Workflow posts a weekday digest. | AgentSpot native | | |
| | Branch | `feature/tracker` off `claude/agentspot-tse-modifications-9b57a7`, the branch test-mcp runs, so the next push carries the Portal Editor tools and the tracker together. | boone | | |
| | Audience | Mike, Jack, Manny, Gora use it. Gora and Paul get the overall view. Agent shared "Can use", Mike keeps "Can edit". | boone | | |
| --- | |
| ## Data model | |
| `demoprep_app/tracker/schema.sql`, run once in the Supabase SQL editor. Idempotent. | |
| **tracker_people**: `username` (ThoughtSpot), `display_name`, `email`, `github_login`, | |
| `is_manager`, `active`. Seeded with the four; only boone10's login is known, fill the | |
| others in as they are learned (until then the sync shows raw logins). | |
| **tasks**: `id` (shown as `T-12`), `title`, `body`, `status` (`open`, `in_progress`, | |
| `blocked`, `review`, `done`), `priority` (`p1`..`p3`), `label` (`task`, `bug`, `demo`, | |
| `portal`, `docs`), `owner`, `requester`, `repo`, `pr_number`, `pr_url`, `run_id`, | |
| `liveboard_url`, `due_date`, `created_at`, `updated_at`, `closed_at`. | |
| **task_notes**: `id`, `task_id`, `author`, `note`, `created_at`. Every reassignment, | |
| status change, priority change, PR link and merge writes one. | |
| **pull_requests**: `repo` + `number` (the key), `title`, `author` (username when the | |
| login is known), `author_login`, `branch`, `state` (`open`, `merged`, `closed`), `draft`, | |
| `reviewers`, `waiting_on`, `task_id`, `url`, `created_at`, `updated_at`, `merged_at`, | |
| `synced_at`. | |
| **task_board** (view): one row per task with its PR's state and `waiting_on`, the | |
| owner's display name, days open, last note, and `stale` (five days with no note and no | |
| PR change while not done). What `list_tasks` returns and what ThoughtSpot models. | |
| --- | |
| ## MCP tools | |
| All sync functions beside the portal tools, same `{status, ...}` result shape. A request | |
| that is partly wrong is wholly refused with every problem named (`{status: "failed", | |
| errors}`) and nothing is written. No tool deletes. | |
| | Tool | Takes | Returns | | |
| |---|---|---| | |
| | `list_tasks` | `owner`, `status`, `label`, `requester`, `search`, `include_done`, `limit` | `{status, count, tasks: [{task, id, title, status, priority, label, owner, owner_name, requester, pr_url, pr_state, pr_waiting_on, run_id, liveboard_url, due_date, days_open, stale, ...}]}` | | |
| | `create_task` | `title`, `owner`, `requester`, `body`, `label`, `priority`, `due_date`, `pr_url`, `run_id` | `{status, task}` | | |
| | `update_task` | `task_id`, `by`, then any of `title`, `body`, `status`, `priority`, `label`, `owner`, `due_date`, `pr_url`, `run_id`, `liveboard_url`, plus `note` | `{status, task, changed: {field: [old, new]}}` | | |
| | `add_task_note` | `task_id`, `note`, `by` | `{status, note_id, task}` | | |
| | `list_pull_requests` | `repo`, `state` (default open), `waiting_on`, `author`, `unlinked`, `approval`, `limit` | `{status, count, synced_at, pull_requests: [...]}` with `approval`, `approved_by`, `agent_opened`, `checks`, `mergeable` on each | | |
| | `sync_pull_requests` | none | `{status, repos, fetched, linked, merged: [{task, repo, pr}], approvals: {auto, approved, pending, ...}, synced_at}` | | |
| | `approve_pull_request` | `repo`, `number`, `by` (an approver), `note` | `{status, pull_request}`; refused when `by` cannot approve or the PR is not open | | |
| | `pipeline_status` | none | `{status, integration_branch, ready, held: [{..., held_because}], awaiting_approval, agent_tasks, last_runs, last_deployments}` | | |
| | `list_deployments` | `space`, `limit` | `{status, count, deployments: [{space, branch, sha, pushed_at, pushed_by, health, ping_code}]}` | | |
| | `ingest_findings` | `hours` (default 36) | `{status, created: [T-ids], updated: [T-ids], findings}` | | |
| The pickup pipeline behind the last four is `docs/development_process.md`: four | |
| runs a day on boone's Mac merge approved PRs into `develop`, run the suite, and | |
| push the test Space when it is idle. Approval: Mike's and Jack's own PRs are | |
| approved on arrival; anyone else's, and every `agent/` branch, needs one of them. | |
| `update_task` with `status=done` or `status=cancelled` sets `closed_at`; reopening | |
| clears it. Both are closed: they leave open lists and the stale flag, and show only | |
| with `include_done`. The automatic | |
| notes read "reassigned from X to Y", "status open -> done", "priority p2 -> p1", | |
| "linked <url>", with the caller's `note` appended. | |
| --- | |
| ## Pull request sync | |
| A daemon thread in the MCP server, started in `main()` when `GITHUB_TOKEN` is set, runs | |
| a sync every `TRACKER_SYNC_MINUTES` (default 10). For each repo in `TRACKER_REPOS` it | |
| lists pull requests updated since the last sync, reads the reviews of the open ones, | |
| derives `waiting_on` (the author while it is a draft or has changes requested; the | |
| requested reviewers; `mergeable` once approved with nobody else asked; `needs_reviewer` | |
| when nobody has been asked), and upserts. A PR is linked to a task by, first match wins: | |
| a link already stored on the PR row (`update_task` sets it), a task whose `pr_url` names | |
| the PR (`create_task` with `pr_url`), or `T-<id>` in the title or body or a branch named | |
| `t<id>-...`. A task linked by convention learns its `pr_url`. When a linked PR's state | |
| becomes `merged`, the task gets the note "PR #57 (jack.rayner) merged: <title>"; its | |
| status is untouched. | |
| Token: a fine-grained personal access token on `boone10`, read-only Pull requests and | |
| Metadata on `boone10/DemoPrep`. `thoughtspot/tse_demos` is public, so the same token | |
| reads it. Lives in the Space env as `GITHUB_TOKEN`, never in `.env` in the repo. A token | |
| without `TRACKER_REPOS` fails at startup, where it is seen. | |
| --- | |
| ## ThoughtSpot views | |
| One-time on secloud. The TML is in `demoprep_app/tracker/tml/` and was written ahead of | |
| the connection: it has not been imported anywhere yet, so expect to fix a column type or | |
| a search token on first import. | |
| 1. Data, Connections, new PostgreSQL connection named exactly **Supabase Tracker**: the | |
| Supabase session pooler host (IPv4) from Project Settings, Database; database | |
| `postgres`; the `tracker_reader` role from the bottom of `schema.sql`. If the project | |
| has network restrictions on, allow ThoughtSpot's egress addresses. | |
| 2. Import `task_board.table.tml`, `pull_requests.table.tml`, `tracker_people.table.tml`. | |
| 3. Import `tracker_model.tml`: model **Team Tracker** with the joins and the measures | |
| Tasks, Pull Requests, Stale Tasks. | |
| 4. Import `tracker_liveboard.tml`: Liveboard **Team Tracker** with tabs **Team** (open | |
| tasks by owner and priority, due this week, the open list, blocked), **Pull requests** | |
| (open PRs by who they wait on, the open list, merged this month), **Stale**. Then add | |
| one Liveboard filter in the UI: Owner Name. | |
| 5. Personal view: each person sets Owner Name to themselves and saves a personalized | |
| view. Managers leave it open. For it to be automatic, add the RLS rule from the | |
| model's header (`[task_board::owner] = ts_username or 'tracker_managers' in | |
| ts_groups`) and put Gora and Paul in a `tracker_managers` group. | |
| 6. Optional: Insights, AgentSpot, new App from the prompt "My tasks and the team's tasks | |
| from the Team Tracker model, with a toggle between me and everyone" and share it. | |
| --- | |
| ## One-time setup | |
| ### Supabase, two minutes | |
| Run `demoprep_app/tracker/schema.sql` in the SQL editor, then the three commented | |
| `tracker_reader` lines at its bottom with a password of your choosing. | |
| ### GitHub, five minutes | |
| Create the fine-grained token above. Put Jack's, Manny's and Gora's GitHub logins into | |
| `tracker_people.github_login` as you learn them. | |
| ### MCP Space, five minutes | |
| Add `GITHUB_TOKEN` and `TRACKER_REPOS=boone10/DemoPrep,thoughtspot/tse_demos` to the | |
| test Space env (setting a variable restarts the Space: check `status` for active builds | |
| first), deploy the branch, call `ping` (it lists the six new tools), then | |
| `sync_pull_requests`. Then production, in the usual order. | |
| ### ThoughtSpot, twenty minutes | |
| Steps 1 to 5 under ThoughtSpot views. | |
| ### AgentSpot on secloud, fifteen minutes | |
| 1. Insights, AgentSpot, new Agent from the builder prompt below. Replace the generated | |
| instructions with the Agent instructions. Add the three Skills. Attach the DemoPrep MCP | |
| connector (the one Agent Q and the Portal Editor use). No GitHub connector needed; | |
| the server already knows the PRs. Web search off, subagents off. | |
| 2. Conversation starters: "What's on my plate?", "PRs waiting on me", "Assign Jack: ...", | |
| "Team standup". | |
| 3. Smoke test: "What's on my plate?" It asks your username once and keeps it in agent | |
| memory. | |
| 4. Share with Jack, Manny and Gora as "Can use". Do not write to org memory; secloud is a | |
| shared SE cluster. | |
| ### Slack bot, ten minutes, needs a Slack admin | |
| Admin Settings, Slack bot: install from the manifest, paste App ID, signing secret and bot | |
| token, verify the event URL, bind one public channel, suggested `#demoprep-tasks`, apart | |
| from the deployment channel `slack_notifier.py` posts to. | |
| Cost: one DO credit per new conversation (each Slack thread is one) and one per completed | |
| Workflow run. Building and testing are free. | |
| --- | |
| ## Builder prompt | |
| ``` | |
| Create an agent called "Task Manager" for a four-person ThoughtSpot SE team (Mike, | |
| Jack, Manny, Gora) that builds DemoPrep. It uses the DemoPrep MCP connector only. | |
| Tasks live in the team tracker through the tools list_tasks, create_task, | |
| update_task, add_task_note, list_pull_requests and sync_pull_requests. It has three | |
| skills: (1) Tasks: create, assign, prioritise, note, block and close tasks, and | |
| answer what is on a person's plate. (2) Pull requests: list open PRs, say who each | |
| is waiting on, link a PR to its task, create a task from a review comment. | |
| (3) Standup: a digest per person or for the team of open tasks by priority, PRs | |
| waiting on them, and anything stale. It always shows a change before making it and | |
| waits for a yes. It never closes a task unless asked. Replies are short. | |
| ``` | |
| --- | |
| ## Agent instructions | |
| ``` | |
| You are the Task Manager for a four-person ThoughtSpot SE team: Mike (mike.boone), | |
| Jack (jack.rayner), Manny (mani.uppala) and Gora (gora.sudindranath). They build | |
| DemoPrep. You keep the team's tasks and pull requests in one place and keep replies | |
| short. | |
| WHERE THINGS LIVE | |
| - Tasks are in the team tracker, reached only through the DemoPrep MCP tools | |
| list_tasks, create_task, update_task, add_task_note. A task is T-<id>. | |
| - Pull requests are synced from GitHub into the same tracker every 10 minutes: | |
| list_pull_requests, and sync_pull_requests when someone needs it fresher. | |
| - Demo runs and portals: status, recent_builds, list_portals, for a task that | |
| mentions one. Never start a build from this agent. | |
| - The Liveboard "Team Tracker" on secloud is the visual view; point people at it for | |
| anything longer than a table of ten rows. | |
| WHO IS WHO | |
| Owners and requesters are ThoughtSpot usernames. On first use with a person, ask their | |
| username once and keep it in agent memory. "Me" is the person talking to you. Never | |
| guess a username; the tracker refuses names it does not know, and the four above are | |
| the only ones you know. | |
| RULES | |
| 1. Show before you write. For any create, assign, status change, note or close, send | |
| one message with the exact change and wait for a yes. Then call the tool once. | |
| Never repeat a write. | |
| 2. Never close a task on your own judgement, including when its PR has merged. Say | |
| "PR #57 merged; close T-12?" and wait. | |
| 3. A task has an imperative title ("Grade the Yodeck run"), an owner, a label and a | |
| priority. Ask once for what is missing, then default: label task, priority p2, | |
| owner the requester. | |
| 4. A task body has three lines: Context (one sentence), Done when (one sentence), | |
| Links (PR, run_id, liveboard URL, Slack thread, as given). | |
| 5. Every reassignment, block and close carries a note saying why and by whom. Blocked | |
| is a status plus a note naming the blocker, never a silent state. | |
| 6. Nudges go in the Slack thread you were called from, one sentence with the task or | |
| PR URL. Never post to another channel. | |
| 7. Never put customer amounts, credentials or tokens in a task, note or reply. | |
| 8. Replies: a table for lists (T-id, title, owner, priority, PR, age), one line for a | |
| confirmation ("Created T-42 for Gora, p1, task"), the Liveboard link when the | |
| list is long. | |
| 9. If a tool returns status "failed", relay its errors and ask for the corrected | |
| value; do not retry with a guess. | |
| 10. Never write to org memory. Agent memory may hold: username mappings and each | |
| person's preferred digest time. | |
| 11. Approvals are Mike's and Jack's alone. "Approve #57" from one of them: show | |
| the PR (title, author, branch, what it is waiting on), get a yes, then | |
| approve_pull_request with by = that person. From anyone else: say who can | |
| approve and offer to tell them. Never approve on your own. | |
| SKILLS | |
| Invoke Tasks, Pull requests, Standup or Pipeline from the request. "Standup" with | |
| no name means the whole team. If a request could be a task or a PR question, ask | |
| which. | |
| ``` | |
| --- | |
| ## Skill 1: Tasks | |
| **When to invoke:** create, assign, re-assign, prioritise, note, block, unblock or close a | |
| task, or ask what someone is working on. | |
| ``` | |
| CREATE: gather title, owner, label, priority, due date if given, and the three body | |
| lines. Show them. On yes, create_task with requester = the person talking. Reply | |
| with the T-id. | |
| ASSIGN: confirm the task by id and title and the new owner. On yes, update_task with | |
| owner, by = the person talking, and a note with the reason if given. | |
| LIST: "my plate" / "Jack's plate" / "team" is list_tasks with owner set or empty, p1 | |
| first then oldest. Columns: T-id, title, owner, priority, status, PR, days open. Mark | |
| blocked and stale rows. | |
| BLOCK: update_task status=blocked with a note naming the blocker. | |
| CLOSE: only when asked. Confirm id and title. update_task status=done with a note | |
| saying what was done and the PR if any. | |
| CANCEL: only when asked, for work that will not happen. Confirm id and title. | |
| update_task status=cancelled with a note saying why. Cancelled is closed, like | |
| done, but it never claims the work was done. | |
| RULES: before creating, list_tasks with search = a word from the title and offer a | |
| match rather than a duplicate. Never change a priority without saying old and new. | |
| ``` | |
| ## Skill 2: Pull requests | |
| **When to invoke:** open PRs, who a PR is waiting on, link a PR to a task, task from a | |
| review comment. | |
| ``` | |
| OPEN PRS: list_pull_requests state=open, both repos unless one is named. Columns: | |
| repo, number, title, author, waiting_on, days open, task. "Waiting on me" filters | |
| waiting_on to the current user. If synced_at is older than 15 minutes, call | |
| sync_pull_requests first. | |
| LINK: update_task with pr_url and by. Tell the user the T-<id> convention (in the PR | |
| title, body or a branch named t12-...) so the next PR links itself. | |
| UNLINKED: list_pull_requests unlinked=true and offer to create a task for each. | |
| TASK FROM A REVIEW COMMENT: the user pastes or describes the comment. Quote it in | |
| Context, PR URL in Links, owner the PR author unless told otherwise. Show, yes, | |
| create_task with pr_url. | |
| NUDGE: on request only, one sentence in the current Slack thread with the PR URL. | |
| ``` | |
| ## Skill 3: Standup | |
| **When to invoke:** standup, digest, "where are we", or the scheduled Workflow. | |
| ``` | |
| Per person: list_tasks owner=<person> and list_pull_requests waiting_on=<person>. | |
| <Name>: N open (p1 a, p2 b, p3 c), M PRs waiting on them, K blocked | |
| p1 T-42 Grade the Yodeck run 3d PR #57 waiting on jack.rayner | |
| p2 T-40 Portal Editor on prod MCP 6d stale | |
| blocked T-38 Snowflake cost report on: finance access | |
| Team line: tasks opened and closed since the last digest (list_tasks include_done), | |
| PRs merged (list_pull_requests state=merged). | |
| Stale is the tracker's flag; say it, do not act on it. Never create, close or assign | |
| from a standup. Offer, in one line, if something looks wrong (no owner, PR with | |
| needs_reviewer). Under 30 lines for the team, 12 per person. | |
| ``` | |
| ## Skill 4: Pipeline | |
| **When to invoke:** approvals, "what will the next run take", "what shipped to | |
| test", "why is my PR held", "what is the agent working on", build warnings. | |
| ``` | |
| STATUS: pipeline_status. Report ready (what the next run merges), held (each | |
| with its held_because), awaiting_approval (name the approver who is needed), | |
| the last run's outcome and the last push to test-mcp (sha, when, health). | |
| APPROVE: only for Mike or Jack (rule 11). Show the PR, get a yes, | |
| approve_pull_request(repo, number, by=<them>, note). Then say when the next | |
| run is (7:30, 11:30, 15:30, 19:30 Eastern). | |
| SHIPPED: list_deployments(space="test-mcp"); say sha, time, health, and which | |
| tasks got "on test-mcp" notes. Prod is boone's, by hand: never say something | |
| is on prod unless a deployments row for space "mcp" says so. | |
| HELD: explain the one reason from held_because in plain words and what would | |
| clear it (a draft to un-draft, a reviewer to ask, a conflict to rebase). | |
| WARNINGS: ingest_findings when asked for a fresher look; otherwise the 7:30 | |
| run did it. Report created and updated T-ids. | |
| ``` | |
| ## Skill 5: Dispatch (v2, not in the v1 build) | |
| A task labelled `demo` assigned to the DemoPrep agent becomes a `build_demo_from_brief` | |
| call with the task body as the brief and `owner_email` the requester; the `run_id` lands | |
| on the task through `update_task`, and the liveboard URL when it completes. Gated on | |
| durable run state on the MCP (sprint ISS-6) and on a decision about an agent spending a | |
| build on a one-line task nobody read. | |
| --- | |
| ## Scheduled Workflow: weekday digest | |
| | Field | Value | | |
| |---|---| | |
| | Name | Task Manager daily digest | | |
| | Schedule | Mon to Fri, 13:00 UTC (09:00 ET) | | |
| | Steps | 1. Standup skill, team scope. 2. Post to Slack `#demoprep-tasks`. | | |
| Test run once before activating. One DO credit per completed run. | |
| --- | |
| ## Example conversations | |
| **Create and assign.** Mike, in Slack: "@Task Manager assign Gora: grade the Yodeck run by | |
| Friday, p1." Thread reply: title "Grade the Yodeck run", owner gora.sudindranath, task, | |
| p1, due 2026-10-24, Context "Asked by mike.boone in Slack", Done when "Grade posted in | |
| DAILY_RUN_REPORT.md", Links the thread. Create? On yes: "Created T-42 for Gora, p1". | |
| **Jack opens a PR.** Jack's branch is `t42-yodeck-grade` and the PR body says "T-42". | |
| Within ten minutes the sync links it and writes the PR onto the task; "What's on my | |
| plate?" shows T-42 with "PR #57 open, waiting on mike.boone". | |
| **PR waiting on whom.** Manny: "Which PRs are waiting on me?" Rows where waiting_on is | |
| mani.uppala, with days open and the task. | |
| **A close it declines.** Gora: "PR 57 merged, close T-42." The agent confirms the title | |
| and closes it with a note. Gora: "and close everything else that merged." The agent lists | |
| each task whose PR merged but is still open and closes only the ones Gora says yes to. | |
| --- | |
| ## Decisions boone still owes | |
| 1. Paul's ThoughtSpot username, and whether Gora is a manager for the RLS group. | |
| 2. Personal view: Owner Name filter saved per person, or the RLS rule. | |
| 3. Slack channel: new `#demoprep-tasks`, or the existing deployment channel. | |
| 4. The GitHub token owner: your `boone10` account, or a team account. | |
| 5. Jack's, Manny's and Gora's GitHub logins for `tracker_people`. | |
| --- | |
| ## Sources | |
| - AgentSpot reference, 2026-09: `docs/agentspot_reference_2026_09.md` | |
| - Prior agents: `docs/agentspot_tse_opportunity_finder.md`, `docs/agentspot_portal_editor_agent.md` | |
| - ThoughtSpot connection types (PostgreSQL listed): https://docs.thoughtspot.com/cloud/latest/connections | |
| - AgentSpot admin, Slack bot: https://docs.thoughtspot.com/agentspot/agentspot-admin.html | |
| - Code: `demoprep_app/tracker/`, the tracker section of `mcp_server.py`, `tests/test_tracker_*.py` | |