Back to home@ddtcorex

dsh-maestro-harness

DSH meta-plugin: automated GitLab MR review + performance audit, and an interactive pair-programming preset.

Stars
1
Language
TypeScript
Created
Aug 18, 2026
Updated
Aug 26, 2026
GitHub repo

Introduction

dsh-maestro-harness

DSH meta-plugin: automated GitLab MR review + performance audit, an interactive maestro-coder pair-programming preset, and full remote access to the DSH web UI from LAN or the public internet through a Cloudflare Tunnel.

See docs/architecture.md for the current architecture and remote-access security model.

What you get

CapabilityHow it works
Intent-driven MR reviewA GitLab assignment or @maestro note hits this machine; Quick requests run the reviewer, Deep requests add the auditor, and inline mentions reply in the originating discussion
Remote access (LAN)The plugin serves a loopback-rewriting reverse proxy on :3081; any device on your network gets the full DSH web UI — sessions, chat, Settings. Open by default, or gated behind a separate LAN PIN
Remote access (public)A Cloudflare Tunnel exposes the same proxy under your own hostname; visitors enter an 8-digit PIN first. cloudflared is resolved automatically (PATH → cache → multi-mirror download) and runs over --protocol http2 so QUIC-blocking networks still work
QR pairingThe Settings → Maestro card shows scannable QR codes for the LAN and public URLs; the LAN URL is the scored best interface (private ranges first, VPN adapters skipped)
Fast remote responsesLarge JSON/text replies are streamed through brotli/gzip, cutting multi-megabyte session histories roughly 10x on slow links
Mobile layoutOn phones the UI becomes a drawer layout with touch-sized targets and safe-area insets (dsh-web-mobile port, MIT)
Tunnel auto-restoreIf DSH restarts while a tunnel was running, it comes back automatically
Telegram PIN updatesOptionally sends protected messages with the current public PIN and initial access status whenever DSH web starts, and with the new PIN after a user explicitly rotates it
Review history & signalsEvery run is recorded in a local history (visible in Settings → Maestro), acknowledged on the MR with award emoji (👀 running → ✅/⚠️ finished), and can send an opt-in Telegram digest when a review finishes
Push re-review (opt-in)After a completed review, new commits pushed to the same MR trigger an automatic Quick re-review — enable it in Settings → Maestro

Requirements

  • Node.js ≥ 22, pnpm
  • A running DeepSeek Harness with the web profile (pnpm dsh web)
  • DEEPSEEK_API_KEY for the review/audit sessions themselves
  • A GitLab account with permission to create project webhooks and personal access tokens
  • maestro-skills installed for DSH when reviewing Magento projects (the installer checks the exact required set; as a plugin, dsh plugin --profile web add github:ddtcorex/maestro-skills serves the skills itself)
  • cloudflared only if you want public access (LAN access works without it)

Companion repository: maestro-skills

The Magento review pipeline is tightly coupled to ddtcorex/maestro-skills — the magento2 review profile loads an exact skill set served by that package:

Required by the magento2 review profileRole
govard-toolboxGovard environment base commands (govard up/sh/db/audit)
govard-magentoMagento-specific container/CLI shortcuts (govard tool magerun, cache, indexers)
magento2-dev-coreArchitecture, DI, security patterns — foundation all findings are fixed with
magento2-code-reviewReview orchestration: scopes + merges QA trio output into one report
magento2-linterPHPCS/PHPStan/PHPMD quality gate (govard audit run --checks lint)
magento2-security-scanStatic vulnerability scanning
magento2-performance-audit9-step performance/infrastructure audit

The generic profile needs none of these. If a required skill is missing at review time, the reviewer fails closed and prints a one-line install command. Install everything as one plugin (no loose files needed):

dsh plugin --profile web add github:ddtcorex/maestro-skills

Install

# from a checkout of this repository
pnpm install
pnpm build              # emits lib/ (the node-half plugins)
pnpm run build:client   # emits client/client.js (the Settings card bundle)

# register the plugins into the web profile (live link: edit + rebuild just works)
dsh plugin --profile web add /path/to/dsh-maestro-harness -w

# copy the three agent presets (not covered by `dsh plugin add`)
./install.sh

Magento review requests load a complete, fixed profile: Govard toolbox and Magento guidance plus code-review, lint, security, and performance checks. If ./install.sh reports a missing skill, install exactly the required DSH skills with the command it prints before enabling review webhooks.

Restart dsh web afterwards. Open Settings → Maestro — if the card appears, the client wiring is working.

Remote Settings compatibility

The plugin works with unmodified DeepSeek Harness releases. For remote access, it marks only PIN-authorized proxy HTML as trusted so DSH can expose its Settings data to that browser. DSH versions that do not recognize __DSH_TRUSTED_PROXY__ remain safe and usable through the proxy, but their Models screen can show settings are unavailable in this browser.

Apply the matching DSH trusted-proxy patch when remote Models/Settings access is required. The marker is ignored by older DSH versions; it does not grant access to the login page or unauthenticated API and WebSocket requests.

Fallback: manual cordis.yml editing

If you're not using the dsh plugin CLI, add these rows to your cordis.yml (paths relative to this package's install location):

- id: maestro-gitlab-webhook
  name: '@ddtcorex/dsh-maestro-harness/lib/gitlab-webhook.js'
  config:
    port: 3000
    secret: !!js process.env.MAESTRO_GITLAB_WEBHOOK_SECRET
- id: maestro-orchestrator
  name: '@ddtcorex/dsh-maestro-harness/lib/orchestrator.js'
  config:
    gitlabBaseUrl: https://gitlab.example.com
    gitlabToken: !!js process.env.MAESTRO_GITLAB_TOKEN
    botUsername: maestro-bot
    projectMappings: []
- id: maestro-tunnel
  name: '@ddtcorex/dsh-maestro-harness/lib/tunnel.js'
- id: maestro-settings-rpc
  name: '@ddtcorex/dsh-maestro-harness/lib/settings-rpc.js'
- id: maestro-client
  name: '@ddtcorex/dsh-maestro-harness'

The last row (package root) is required — the client-modules registry only scans loader entries whose name resolves to a package root, so without it the Settings card never mounts.

Set up on a new machine

All values below are placeholders — replace gitlab.example.com, group/project, dsh.example.com, and every token with your own. Nothing real belongs in this repo or its config files.

1. GitLab personal access token

Create a personal access token with the api scope (GitLab → Preferences → Access Tokens). You will paste it into the Settings UI in step 3 — it is stored owner-only (0600) under $DSH_HOME/dsh-maestro-harness/config.json.

2. Boot environment

The webhook's shared secret can come from the environment or from the Settings UI (Settings wins, effective immediately):

export MAESTRO_GITLAB_WEBHOOK_SECRET='generate-a-long-random-string'   # optional if set in Settings
export MAESTRO_GITLAB_TOKEN='glpat-not-a-real-token'   # optional fallback; Settings UI wins
pnpm dsh web --no-open

Put both lines in whatever you use to persist env (shell profile, systemd unit, .env consumed by your launcher). Never commit them.

3. Configure via Settings → Maestro

  • GitLab: base URL (https://gitlab.example.com), the token from step 1, and the GitLab service-account username (for example, maestro-bot). This username is matched when GitLab assigns a reviewer. Use that account's PAT too if comments should be authored as maestro.
  • Projects: map each GitLab path to its local checkout, e.g. group/project/home/you/work/project. The automated pipeline only reacts to mapped projects. Each row can also override the review model.
  • Review model (optional): pick the provider/model (and reasoningEffort) for automated reviews from the dropdown catalog. Leave empty to use the DSH default. A per-project override beats the global choice.

Values saved here override the cordis.yml row config at runtime and take effect on the next webhook delivery without a restart.

4. Register the webhook in GitLab

One endpoint serves every repository: each delivery names its project in project.path_with_namespace, and the orchestrator reacts only to projects mapped in Settings → Maestro. Register the same URL and secret on each project you want covered, or once at group level to cover all of them.

Per project (or at group level): Settings → Webhooks →

  • URL: https://<your-public-hostname>/hooks/gitlab-mr
  • Secret token: the effective webhook secret — webhookSecret from Settings → Maestro, or MAESTRO_GITLAB_WEBHOOK_SECRET if Settings has none (step 2)
  • Trigger: Merge request events and Comment/Note events
  • SSL verification: enabled (Cloudflare certificates validate fine)

Create a GitLab service account (or use an existing bot account), configure its exact username in Settings, grant it permission to review and comment in the project, and assign it as a reviewer. A new assignment starts a Quick whole-MR review. An MR-level @<botUsername> mention (for example, @maestro-bot) also starts Quick; add /maestro deep to request Deep review. An inline @<botUsername> mention reviews only that discussion's changed line and replies in the same thread. The literal token remains supported before the service account exists, but it is not a real GitLab mention and cannot be assigned as a reviewer.

For an unmapped project, only an explicit @<botUsername> mention starts a Quick diff-only review. It reads the GitLab diff and labels the result as having no local checkout, Magento environment, static analysis, or tests. A reviewer assignment remains a no-op, and /maestro deep posts a request to add a project mapping rather than pretending to run a full review.

Until step 5 is done, use a temporary URL of http://<machine-LAN-IP>:3000/hooks/gitlab-mr if GitLab can reach your machine directly.

5. Public access via Cloudflare Tunnel (one-time)

Skip entirely if LAN-only access is enough.

cloudflared tunnel login                      # opens a browser; pick your domain
cloudflared tunnel create dsh-home            # prints the tunnel ID
cloudflared tunnel route dns dsh-home dsh.example.com

Then in Settings → Maestro: switch Tunnel mode to Named, paste the Tunnel ID, the credentials file path (~/.cloudflared/<tunnel-id>.json), and the hostname (dsh.example.com). Press Start tunnel — the plugin generates the ingress config itself:

  • <hostname>/hooks/* → the webhook server (:3000)
  • everything else on <hostname> → the remote-access proxy (:3081, which forwards to the DSH web UI on 127.0.0.1:3080)

The public address demands the access PIN shown in the card (8 digits, stored at $DSH_HOME/dsh-maestro-harness/token, mode 0600). It survives tunnel and DSH restarts; use Rotate in Settings → Maestro when you need to invalidate it. Update the GitLab webhook URL to https://dsh.example.com/hooks/gitlab-mr now that DNS exists.

Do not run a second manual cloudflared alongside the plugin-managed one — two connectors on one tunnel route inconsistently.

6. Verify end-to-end

  1. Assign the configured maestro user as reviewer, or write @maestro in an MR comment in a mapped project. Add /maestro deep for the full audit. For an unmapped project, use a mention only to request the explicitly labelled diff-only Quick review.
  2. Within seconds the orchestrator creates a worktree under the mapped clone; Quick runs the reviewer and Deep runs reviewer + auditor. An inline command replies in the original discussion.
  3. From a phone on the same network, scan the LAN QR in Settings → Maestro — the full DSH UI should load without any PIN.
  4. From an external network, open https://dsh.example.com, enter the PIN, and confirm the session list appears.

If something doesn't work, see Troubleshooting.

Manually reviewing an already-existing MR

The automated pipeline only reacts to live webhook deliveries. To re-review an older MR:

MAESTRO_GITLAB_BASE_URL=https://gitlab.example.com \
MAESTRO_GITLAB_TOKEN=glpat-not-a-real-token \
MAESTRO_GITLAB_WEBHOOK_SECRET=the-same-secret-as-step-2 \
./bin/maestro-review.mjs --project group/project --mr 42

This looks the MR up via the GitLab API and POSTs the same payload shape the real webhook produces to the running server's /hooks/gitlab-mr/trigger route — the pipeline that runs is identical.

Agent presets

./install.sh copies three presets into ~/.dsh/.agent-presets/:

PresetRole
dsh-maestro-reviewerReviews the MR diff and posts findings
dsh-maestro-auditorPerformance audit pass over the changed code
dsh-maestro-coderInteractive pair-programming agent (available in the Web GUI agent picker immediately)

Re-run ./install.sh after pulling preset changes.

Configuration reference

Runtime-configurable from Settings → Maestro (stored in $DSH_HOME/dsh-maestro-harness/config.json, overrides cordis.yml):

FieldMeaning
gitlabBaseUrl / gitlabToken / botUsernameGitLab API coordinates for the review pipeline. Secrets saved from Settings are stored server-side and never echoed back — the card shows only whether one is saved
projectMappingsprojectPath → localRepoPath → reviewProfile → reviewModel mappings used for full local reviews; profiles are magento2 (full Magento skill set) or generic (no skills required). A mapping's localRepoPath must be an absolute path to an existing git checkout, validated on save. reviewModel is an optional per-project override ({provider, model, reasoningEffort?}) that takes precedence over the global review model. An unmapped explicit mention receives a limited diff-only Quick review
reviewModelGlobal model override for automated reviews ({provider, model, reasoningEffort?}) — e.g. deepseek-official / deepseek-chat. When absent the DSH default model (ctx.agentDefaultModel) is used; per-project reviewModel in projectMappings overrides this value. Dropdown catalog is served from maestro.models.list; reasoningEffort is low/medium/high when the model supports it
webhookSecretWebhook auth (X-Gitlab-Token), re-read per request; overrides MAESTRO_GITLAB_WEBHOOK_SECRET without a restart. Must match the GitLab webhook's Secret token
autoRereviewOnPushOpt-in: after a completed review, further pushes to the same MR trigger an automatic quick re-review (default false)
agentTimeoutMsHard ceiling on one automated review agent's turn, minimum 1000 ms (default 20 minutes). A hung agent is disposed and the review recorded as failed
reviewSessionRetentionDaysPrune Maestro's own review history (reviews.json) and failed-report files older than this many days; 0 keeps everything forever (default). DSH session transcripts are never touched
tunnelModequick (ephemeral trycloudflare URL) or named (your hostname)
quickTargetWhat a quick tunnel exposes: dsh-web or webhook
tunnelId / tunnelCredentialsFile / tunnelHostnameNamed-tunnel coordinates from the one-time setup
proxyPort / proxyHostRemote-access proxy bind, default 3081 on 0.0.0.0 (set proxyHost: 127.0.0.1 to disable LAN exposure); when the port is busy the proxy walks up to ten ports instead of failing
lanPinEnabledGate LAN access behind a second PIN (default false — LAN stays open). The LAN PIN lives in its own token-lan file, so rotating the public PIN never invalidates LAN links
telegramBotToken / telegramChatIdOptional Telegram Bot API credentials for one fixed chat. Enter both in Settings → Maestro; leave either blank to disable it. Telegram sends the public PIN, proxy/LAN status, and tunnel URL/status on boot, then the new PIN after a user presses Rotate
telegramReviewNotificationsOpt-in digest: one protected message per finished review with its outcome and a short summary (default false)
lastTunnelRunningManaged by the plugin; drives auto-restore on boot

Environment variables:

VariableConsumed by
MAESTRO_GITLAB_WEBHOOK_SECRETWebhook auth fallback (X-Gitlab-Token) and the manual-review CLI; optional if webhookSecret is set in Settings, which wins per request
MAESTRO_GITLAB_TOKEN, MAESTRO_GITLAB_BASE_URLOrchestrator fallback when Maestro Settings has no value, and the manual-review CLI; the token is optional at boot
MAESTRO_TRIGGER_URLManual-review CLI target, default http://localhost:3000/hooks/gitlab-mr/trigger

Mobile layout

Phone/tablet adaptation of the DSH web shell is owned by the external dsh-web-mobile plugin, installed in the web profile (~/.dsh/profiles/web/package.json, tracking upstream main), not by this repository. After any profile update or restart: verify once in a mobile-emulating browser (Chrome /opt/google/chrome/chrome, isMobile + hasTouch, viewport 390×844): drawer open/close, composer, market page, Maestro settings stacking.

Only the Maestro-rendered settings card keeps local adaptation (client/mobile-maestro.css.ts); problems elsewhere go upstream as PRs to dsh-web-mobile, not patches here.

Security notes

  • The remote-access proxy rewrites Host/Origin to loopback, which unlocks DSH's privileged RPCs remotely. The PIN gate is therefore the only authentication on the public path — treat the PIN like a password and rotate it if a link leaks (the Rotate button does this without restarting).
  • PIN checks and webhook-secret comparison run in constant time (sha256 digest
    • timingSafeEqual), and failed public-PIN logins are rate limited per source address: five failures per ten minutes earn a 429 with a Retry-After header; a successful login resets the counter.
  • LAN access is unauthenticated by default (same trust model as your network). On shared networks either set proxyHost: 127.0.0.1 or enable Require a PIN on the LAN in Settings → Maestro, which gates LAN hosts behind a separate rotating PIN.
  • GitLab tokens and the webhook secret never appear in this repository; they live in 0600 files under $DSH_HOME or your boot environment.
  • Settings saves are validated server-side: unknown keys are rejected, mapping paths must be existing git checkouts, and stored secrets are never returned to the browser — the card shows only a "saved" marker plus a Clear action.
  • Review history (reviews.json) and failed reports live under $DSH_HOME with owner-only permissions; they record project/MR/outcome metadata only, never tokens or MR content.
  • Telegram bot tokens are also stored owner-only in the Maestro config and are never written to logs. Telegram startup messages contain the public access PIN; send them only to a private chat you control. The bot API request uses Telegram's protect_content option, but it is not a substitute for choosing a trusted destination.

Troubleshooting

SymptomLikely cause / fix
No Maestro card in SettingsThe package-root row (maestro-client) is missing from your composition, or the client bundle wasn't built (pnpm run build:client)
Models says settings are unavailable in this browser through the tunnelThe installed DSH does not recognize the authenticated-proxy marker. The plugin and tunnel still work; apply the matching DSH trusted-proxy patch to enable remote Models/Settings
Session list empty via the tunnelYou are hitting dsh web directly instead of the proxy; the tunnel's non-hook ingress must point at :3081
Public URL asks for a PIN you don't knowRead the current one via Show in Settings → Maestro (from localhost or LAN), or use Rotate if you need to replace it
Tunnel fails with "download failed on all sources"cloudflared isn't on PATH and every mirror failed — install it manually (npm i -g cloudflared, brew install cloudflared, or winget install cloudflared) or place the binary at $DSH_HOME/dsh-maestro-harness/bin/cloudflared
Tunnel URL unreachable from a phone but the process runsMany networks block cloudflared's default QUIC transport; the plugin already forces --protocol http2 (TCP 443). If it still fails, the network likely blocks that too — try a different network or a named tunnel
Tunnel was running, now shows an errorThe cloudflared process exited; the status card shows the exit code. Start the tunnel again — a quick tunnel gets a fresh URL
Proxy port busy at bootThe proxy automatically moves to the next free port (up to ten tries); the actual port appears in the LAN URL on the card
The LAN URL on the card opens nothing from a phoneThe advertised address is the scored best interface (private ranges preferred, VPN/virtual adapters penalized) — if your phone is on a guest/VLAN network it cannot reach that address; use the tunnel instead
Large session history loads slowly over the tunnelResponses are compressed (brotli/gzip) automatically; if a client shows garbled JSON, it sent an accept-encoding it cannot actually decode — that is a client bug, not the proxy
Webhook returns 401X-Gitlab-Token doesn't match the effective secret — webhookSecret from Settings if set, otherwise MAESTRO_GITLAB_WEBHOOK_SECRET; with neither configured, every request is rejected
PIN page answers 429Five failed PIN attempts from your address in ten minutes; wait for the Retry-After window (a successful login resets the counter)
MR changed but nothing happensThis is expected unless the configured bot is newly assigned as reviewer or a note contains @<botUsername>; assignments still require a project mapping, while an unmapped mention runs only the labelled diff-only Quick review. Pushes re-review only when Re-review when new commits are pushed is enabled and a review of that MR already completed. Confirm MR + Comment/Note events are enabled.
Settings rejects a saveThe payload failed server-side validation — the error names the key or path: unknown keys, non-absolute or non-git localRepoPath, out-of-range webhookPort/agentTimeoutMs
Port 3000 already in useAnother service owns the webhook port; change the port config on the maestro-gitlab-webhook row and the mapping accordingly

Contributing: Superpowers workflow (required)

All changes to this repository follow the Superpowers skill workflow. Agents and humans contributing here are required to comply with it:

  1. brainstorming — explore intent, requirements, and design before touching code; write the outcome to docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md.
  2. writing-plans — turn the approved spec into a numbered, task-by-task plan (each task lists its failing test first) at docs/superpowers/plans/YYYY-MM-DD-<topic>.md.
  3. executing-plans — implement one task at a time in strict TDD: failing test → RED → implement → GREEN → commit that task as its own commit.

Rules of thumb enforced by AGENTS.md: never batch multiple tasks into one commit; never commit while a task's tests are red; keep specs and plans under docs/superpowers/ as the durable design record; tunnel/proxy tests must bind hermetic servers on port 0 because a live DSH web often occupies :3080.

Test

pnpm test