dealdash-agent-bridge is the single repo-local plugin that gives agents a safe DealDash tool surface. It is designed for Claude Code, OpenAI/Codex or ChatGPT MCP clients, OpenClaw, and future agent hosts.
OpenClaw is treated as an optional WhatsApp and Telegram adapter, not as the core identity of the system.
Human operators should start with Connect An AI Agent or the in-app /tools/ai-agent-setup page. This page is the agent-optimized reference for exact tool names, auth headers, and safety rules.
One Plugin Model
There is one active DealDash agent path:dealdash-agent-bridgeMCP tools, when the host has MCP configured.- Direct HTTPS calls to the same
/api/agent/*backend, when MCP is not live but the host can make HTTPS requests.
Architecture
- DealDash agent core: canonical
/api/agent/*backend contract with acting-user scoped access. - MCP server: provider-neutral stdio server in
/plugins/dealdash-agent-bridge/scripts/server.ts. - Channel adapters: optional messaging integrations that normalize attachments, capture approvals, and apply channel tone.
Backend Auth
Normal user setup uses login-link auth:- The MCP bridge calls
POST /api/agent/auth/start. - The agent sends the returned DealDash approval link to the user.
- The user opens the link, signs in, and approves.
- The bridge polls
GET /api/agent/auth/status/:requestId?deviceCode=.... - After approval, the bridge stores the scoped token inside the MCP process.
auth.authorizeUrl to the user, keep
auth.deviceCode and any approved token inside its tool/session state, and
poll auth.statusEndpoint after the user approves. A normal user setup must not
be blocked on DEALDASH_AGENT_SERVICE_SECRET, DEALDASH_AGENT_DEFAULT_USER_ID,
or deployment provider settings.
After login-link auth, direct HTTPS clients call /api/agent/* with the stored
login token:
authorization_pending, access_denied,
expired_token, and invalid_grant.
OAuth scopes are allowlisted. New full-bridge clients default to
dealdash.read dealdash.write.low_risk dealdash.memory; clients that request
unknown scopes are rejected with invalid_scope. Read tools require
dealdash.read, Tier 1 operational writes require dealdash.write.low_risk,
and sensitive routes require dealdash.write.sensitive or mcp plus the
existing approval gate. The approval page shows the stored request snapshot:
client name, client URL, requested scopes, expiration, and a warning when mcp
requests full bridge access.
If agent_auth_status reports connectionState: "token_already_claimed"
without returning a new stored token, the approval link was already claimed by a
different agent process. Start a fresh login-link authorization instead of
claiming that the current session is connected.
Operator-managed adapters can still use gateway-delegated authentication.
Authorization: Bearer <DEALDASH_AGENT_SERVICE_SECRET>x-dd-acting-user-idx-dd-channelx-dd-actor-idx-dd-request-idx-dd-approval-idfor sensitive writes
APP_ORIGIN first, then deployment fallback
origins if needed; the short-link domain is not the preferred approval origin.
Operators can set
DEALDASH_AGENT_WRITE_CONFIRMATION_MODE=allow_non_delete_writes when an agent
should run non-delete write tools without repeated approval prompts. Delete
operations always require approval confirmation, regardless of this mode.
Operators can verify the safe bring-your-own-agent surface inside DealDash at /settings -> AI Agent Connection. The Settings card shows connection status, .mcp.json path, MCP command, login-link endpoints, permission tiers, tool families, and recent scoped logs without exposing secret values.
The private DealDash Agent Kit repository is djasha/dealdash-agent-kit. It contains agent Markdown instructions, skill files, and MCP setup notes for agents. It must never contain real secrets, user data, production tokens, database URLs, or private local paths.
Public Discovery
Agents should discover the bridge from the live website before assuming route shape:- API catalog:
https://dealdash.neonoir.ai/.well-known/api-catalog - OpenAPI description:
https://dealdash.neonoir.ai/openapi.json - OAuth authorization server:
https://dealdash.neonoir.ai/.well-known/oauth-authorization-server - OAuth protected resource:
https://dealdash.neonoir.ai/.well-known/oauth-protected-resource - MCP server card:
https://dealdash.neonoir.ai/.well-known/mcp/server-card.json - Shortener-only MCP server card:
https://dealdash.neonoir.ai/.well-known/mcp/drdj-shortener/server-card.json - A2A Agent Card:
https://dealdash.neonoir.ai/.well-known/agent-card.json - Agent Skills index:
https://dealdash.neonoir.ai/.well-known/agent-skills/index.json - Skill Markdown:
https://dealdash.neonoir.ai/.well-known/agent-skills/dealdash-agent-bridge/SKILL.md - Shortener Skill Markdown:
https://dealdash.neonoir.ai/.well-known/agent-skills/drdj-shortener/SKILL.md - Web Bot Auth key directory:
https://dealdash.neonoir.ai/.well-known/http-message-signatures-directory
/api/agent/* responses include a WWW-Authenticate challenge
with resource_metadata pointing at the OAuth protected-resource metadata.
Public marketing pages support Accept: text/markdown for compact reading.
Browser agents can use WebMCP only for public bootstrap tools: schema fetch,
public OAuth registration/device authorization, public Markdown reads, and
canonical setup/documentation links. Browser WebMCP does not expose account
read/write tools in V1.
Run pnpm agent:mcp-install:check --json before copying setup instructions or
refreshing a local Codex plugin install. The check verifies the repo MCP config,
boots the configured server without tokens, and, when a local Codex plugin cache
exists, fails if that cache is stale or missing current tools such as
linkshot_evidence. After a cache refresh, start a new Codex session or reload
the agent host before validating deferred tool discovery; existing conversations
can keep the old tool list.
Tool Families
- Short links: create from URL, list, get, stats, delete
- Screenshots: upload photo, capture URL, reserve, link to deal, get, latest, delete
- Deals: search, get, latest, create, update, find by URL, due views, view logs, create view log, bulk add view checks, progress
- Payments: list, create, update, delete
- Tasks: list, get, latest, create, complete, reopen
- Contacts: search, get, latest, upsert, by phone, deals, notes, labels, counts, duplicates
- Influencers: search, get, latest, upsert, by phone, by promo code, stats, last progress
- Activity: feed and analytics
- Suggestions: pipeline summary, next actions, payment followups, content followups
- Templates: message templates, latest story message template, and reusable deal templates
- Context: search and resource hints
- Memory: list, create, archive
- LinkShot evidence: packet from screenshot/candidate, rank search results, rank candidates, summarize screenshot examples, plan video search, plan proof capture, proof-run harness packages, format verification report, audit workflow readiness, workflow report
- Approvals: request and status
readOnlyHint, destructiveHint, idempotentHint, and openWorldHint.
Read-only tools are marked read-only/idempotent. Mixed read/write tools stay
conservative; update, upsert, archive, status-transition, and delete-capable
families set destructiveHint: true, and tools that can shorten or capture
external URLs set openWorldHint: true.
Successful MCP tool results return the same JSON object in structuredContent
and as serialized text content. Keep both surfaces aligned so modern MCP hosts
can parse structured results while older clients can still read the text block.
MCP-safe error results use isError: true with JSON text containing error,
code, status, and safe details; they must not echo authorization headers,
service secrets, image data, or stored login tokens.
MCP Resources And Prompts
The MCP server exposes fixed resources for hosts that supportresources/read:
dealdash://context/search: default search across recent accessible DealDash context.dealdash://linkshot/view-logs: recent LinkShot View Logs.dealdash://memory/active: active human-visible agent memory.
dealdash_read_only_start: start with context search, screenshots, View Logs, and due views.dealdash_image_to_link: guide a safe image upload and short-link return flow.dealdash_linkshot_evidence_packet: normalize screenshot, candidate, view-count, and direct-proof signals before any LinkShot view-log write.dealdash_linkshot_video_proof_search: guide a/grillme-style proof run from read-only context through candidate ranking, proof capture, final report, and readiness audit.
Approval Tiers
- Tier 0: reads only
- Tier 1: low-risk writes such as short-link creation, screenshot upload, screenshot linking, LinkShot bulk view-check imports, task state changes, and note creation
- Tier 2: sensitive writes such as direct deal create/update/delete, payment CRUD, contact deletes, screenshot deletes, and visibility changes
x-dd-approval-id.
DEALDASH_AGENT_WRITE_CONFIRMATION_MODE=allow_non_delete_writes removes that
approval requirement for non-delete Tier 2 writes when the operator explicitly
enables it. Delete operations always require approval. For OpenClaw messaging
flows, Telegram approval evidence should be captured by the adapter before
confirming the approval record. Confirmation is not exposed as a generic MCP
tool and requires DEALDASH_AGENT_APPROVAL_CONFIRM_SECRET plus
x-dd-approval-confirm-secret.
Agent-routed deal create/update calls persist through the same backend routes as
dashboard edits. Successful writes leave the normal domain activity row with
payload-safe agent metadata (agentSource, request id, actor id, channel,
operation, approval tier, and approval id) and a separate payload-safe
agent_tool_call row with request metadata plus response-derived deal IDs,
deal name, promo code, status, and LinkShot bulk-import summary IDs/counts when
available. Agent-routed screenshot reserve/upload/link writes add payload-safe
proof handles such as
screenshotId, shortId, dealId, videoId, sourceUrl, platform,
detectedViews, pending, and uploaded, without logging raw image data,
storage paths, public image URLs, or rendered shortUrl/directUrl values.
V1 Exclusions
V1 intentionally does not expose admin/auth/team tools, runtime execution, filesystem tools, or bulk destructive operations. URL screenshot capture accepts onlyhttp and https URLs and blocks local/private targets by default. Use DEALDASH_AGENT_ALLOW_PRIVATE_CAPTURE_URLS=true only for trusted development capture.
Photo uploads accept PNG, JPEG/JPG, WebP, GIF, AVIF, and BMP raster images by default. The MCP bridge enforces DEALDASH_AGENT_MAX_IMAGE_BYTES before sending the payload to DealDash. The current default binary image limit is 40MB; the DealDash API JSON body limit has 64MB headroom for base64 encoding. Raise those limits only in controlled deployments because base64 uploads are memory-heavy.
SVG, HEIC, and TIFF are not accepted by default. SVG can contain active content, and HEIC/TIFF are not reliably previewable in browser-based DealDash screenshot galleries. Messaging adapters should convert those formats to PNG/JPEG/WebP before calling screenshots.upload_photo.
LinkShot Evidence Workflow
Uselinkshot_evidence before any persistent view-log write from searched or
captured video evidence. The safe sequence is:
- Read current DealDash context with
context.search,deals.due_views,deals.view_logs, andscreenshots.list_latest. - Summarize prior screenshots with
summarize_screenshot_examplesas capture references only. - Call
plan_video_searchbefore browser or platform search. - Follow the returned
browserSearchTargets, gather thecandidateIntakeFields, and fillrankingInputTemplatefor each raw candidate. - Call
audit_browser_candidate_intakebefore ranking so missing video/account/date fields, transcript cue gaps, and direct-proof gaps stay visible. - When transcript, caption, or first-comment text is available, call
extract_transcript_cuesand copycandidatePatch.transcriptMentionAtSecondsinto the candidate as a navigation cue only. - Rank raw results with
rank_search_resultsor normalized candidates withrank_candidates. - Call
plan_proof_captureto turn ranked rows into explicit screenshot jobs with selector hints, metadata templates, direct-proof state, and missing write requirements. - Capture or upload the current proof screenshot with
screenshots.capture_urlorscreenshots.upload_photo. - Pass current captures as
proofScreenshots, not historicalscreenshots, so the tool matches proof to the correct video URL. - Call
plan_direct_proof_reviewbefore claiming confirmation; transcript, caption, comment, and link matches stay navigation-only. - Finish with
workflow_reportfor the operator report plus readiness audit.
observedPromoAtSeconds. The screenshot sourceUrl must canonically match the
same platform video id/permalink as the source video URL; profile, reels,
shorts, or grid screenshots are review evidence only.
Final format_verification_report, workflow_report, and
audit_workflow_readiness responses include top-level verificationRows and
verificationLinks when candidate rows are supplied; use those fields for the
operator handoff so each source video URL stays beside its screenshot id/link
and write-gate state without parsing Markdown report text.
Before broad /grillme automation, use
pnpm agent:native-automation:check --json,
pnpm agent:smoke:primitives --mock --json, or the default
pnpm agent:readiness:check --json gate to prove the native/local automation
catalog and core primitive tools. The native catalog is static and no-write; it
emits nativeAutomationFormat: dealdash-native-automation-catalog-v1, verifies
DJA-130 native/local replacements and Apify escalation policy, and must keep
nativePathCoverageStatus: complete, apifyPolicyStatus: documented,
liveWrites: false, and persistentViewLogWrites: false. The primitive JSON
contract must expose contextSearch, dueViews, viewLogs, urlShortLink,
imageUploadShortLink, screenshotCapture, and a three-row
verificationLinks set so agents can see the source URL, returned short link,
uploaded image short link, and specified screenshot capture proof separately.
Use the mock workflow smoke before claiming the flow is ready:
screenshots.capture_url, and feeds the same proofScreenshots contract used
by live collectors.
For a no-write live pass against explicit platform URLs, run:
pnpm agent:preflight:linkshot-live --mock --json for validation. Add
--from-due-views to validate read-only due-view URL seeding when no explicit
--url is available. The preflight opens only supplied HTTP(S) URLs or
candidate URLs resolved from deals.due_views, blocks local/private targets by
default, extracts candidate fields, and runs the LinkShot plan, intake,
transcript-cue, ranking, proof-capture handoff, and direct-proof review helpers.
It keeps
liveWrites: false and proofCapture: false; it does not search platforms,
capture/upload proof images, create short links, or write view logs. Use
proofCapturePlan.jobs as the next screenshot handoff.
Use
pnpm agent:preflight:linkshot-live --mock --from-plan-targets --discover-candidates --json
to validate planned account-page discovery. With --from-plan-targets, the
preflight opens URL-bearing account_page targets returned by
plan_video_search.browserSearchTargets, reports planTargetSeed, and does not
open broad web/platform search targets or write anything.
Before using this mode for a /grillme run, read
plan_video_search.requestReadiness
(linkshot-grillme-request-readiness-v1). It must show browser search or
account discovery readiness, or else use its missing fields and operator
question instead of guessing the date, promo/query anchor, or account URL.
Use pnpm agent:preflight:linkshot-live --mock --mock-structured-metadata --json
to validate structured video metadata fallback extraction without screenshots,
short links, or view-log writes.
Use pnpm agent:preflight:linkshot-live --mock --discover-candidates --json to
validate account/search-page discovery. With --discover-candidates, supplied
URLs are treated as explicit pages to inspect for linked video candidate cards;
rows are marked collectorSource: explicit_page_discovery, deduped by video
URL, and passed through the same read-only gates. It does not run platform
search beyond those supplied pages.
Use
pnpm agent:preflight:linkshot-live --mock --discover-candidates --enrich-discovered-candidates --json
to validate capped detail-page enrichment. With
--enrich-discovered-candidates, discovered candidate detail URLs are opened up
to --enrich-limit (default 5) to fill sparse caption, first-comment,
transcript, view-count, and direct-proof fields. It is still bounded to the
supplied-page results and does not capture screenshots, create short links, or
write view logs.
Detail-page extraction reads visible DOM first and then falls back to JSON-LD or
known app-state/player JSON scripts for source URL, account, title,
caption/description, transcript, published date, video id, and view count. When
visible/structured transcript text is missing, it may read standard
caption/subtitle track files from DOM <track> tags or app-state/player JSON
such as YouTube timed-text captionTracks, and mark candidates with
transcriptSource: caption_track, track URL, kind, label, language, and track
source. Structured and caption-track transcript/caption cues remain
navigation-only and must not be copied into direct-proof fields.
Use pnpm agent:preflight:linkshot-live --mock --capture-proof --json to
validate the explicit screenshot step. With --capture-proof, the command
consumes the handoff jobs, calls screenshots.capture_url, and passes returned
screenshot metadata back into workflow_report as proofScreenshots. It can
create screenshot proof records and short screenshot links, but it still keeps
persistentViewLogWrites: false and does not write LinkShot view logs.
Imported or extracted screenshotSelector, waitForSelector, and
captureClip hints are preserved on the matching capture job as
candidateCaptureHint, while an explicit CLI --selector remains the operator
override. If the screenshot API response omits sourceUrl, the preflight
preserves the source video URL from the capture job so operator rows still keep
the video link beside the screenshot link.
Use pnpm agent:preflight:linkshot-live --mock --mock-caption-track --json to
validate caption/subtitle track cue extraction without screenshots, short links,
or persistent view-log writes.
Use
pnpm agent:preflight:linkshot-live --mock --mock-app-state-caption-track --json
to validate app-state/player JSON caption-track extraction without screenshots,
short links, or persistent view-log writes.
The default pnpm agent:readiness:check --json gate runs both focused
browserless caption-track preflights; use
pnpm agent:readiness:check --only preflight_caption_track,preflight_app_state_caption_track --json
when validating transcript cue handling alone. These checks import
deterministic caption-track candidate fixtures instead of launching Playwright,
must keep persistentViewLogWrites and proofCapture false, and summarize
transcript cue counts without treating the cue as direct proof. The raw
--mock-caption-track and --mock-app-state-caption-track commands remain the
browser-backed extraction checks for runners with Playwright browsers installed.
Use
pnpm agent:readiness:check --only proof_capture_rehearsal --json
to validate the CI-stable browserless no-view-log-write rehearsal: imported
candidate rows, one proof screenshot, workflow_report, and
directProofReviewPlan.
Use
pnpm agent:preflight:linkshot-live --mock --discover-candidates --enrich-discovered-candidates --capture-proof --capture-limit 1 --json
only when Playwright browsers are installed and you also need to exercise
explicit page discovery plus capped detail enrichment before capture. The
report must keep screenshot links beside source video URLs and keep
transcript-only or missing-screenshot rows blocked. The
preflight also exposes top-level verificationRowsFormat: linkshot-live-preflight-verification-row-v1 and verificationRows; use those
rows for operator output because each row keeps source video and screenshot
verification links together with direct-proof review status, suggested seek
seconds, review window seconds, and no-write reason.
Use pnpm agent:inventory:linkshot-screenshots --mock --json to validate the
historical screenshot example inventory. Live mode is read-only and calls
screenshots.list_latest before linkshot_evidence.summarize_screenshot_examples.
The command outputs screenshot IDs, short links, source video URLs,
platform/deal/promo metadata, detected views, capture patterns,
missingForTraining, and next actions. It omits raw image payloads, OCR text,
storage paths, owner names, and public image URLs by default. Add
--include-view-logs when the inventory needs dated LinkShot view-log rows,
response-level viewLogCopyText, the extension-compatible copyTextFormat, and
verificationRows that keep checkedAt, logId, source video URL, screenshot
short link, views, and copy text together. --from, --to, --q, and
--log-id narrow the view-log read. Rows missing source or screenshot links are
marked needs_metadata for curation. Treat the output as capture-framing
examples only; current video proof must still be captured fresh and supplied as
proofScreenshots.
The default readiness gate also runs
pnpm agent:inventory:linkshot-screenshots --mock --include-view-logs --date 2026-04-10 --json
so dated example selection, verificationRows, and
linkshot-extension-completed-copy-v1 copy text stay covered by the main
/grillme health check.
Symphony Pilot Guardrail
DealDash has a repo-owned/WORKFLOW.md for openai/symphony-style Linear/Codex
orchestration. Treat it as the dispatch contract for pilot runs. It only allows
safe Todo issues in the Symphony: LinkShot Evidence Agent project with
label symphony-pilot, max concurrency 1, no deletes, no payments, no
external messages, and no persistent LinkShot view-log writes.
Validate changes with:
Template Reads
Usetemplates.latest_story_message when the user asks for the latest story copy, story message, or “latest story from templates”. Use templates.list_message with tag=story if the latest endpoint returns empty. Use templates.list_deal or templates.latest_deal for reusable deal/package templates.
Template reads are Tier 0 and remain scoped to the acting user.
LinkShot View Logs
deals.view_logs is a Tier 0 read operation routed through
/api/agent/deals/view-logs. It mirrors the website’s /screenshots View Logs
tab and supports scope, dealId, videoId, logId, from, to, q,
limit, and offset filters.
Responses include response-level copyText for the returned page/filter and
per-row copyText for exact log verification. Both use
copyTextFormat: "linkshot-extension-completed-copy-v1", matching the LinkShot
extension completed-copy action and the website View Logs copy buttons.
Website deep links such as
/screenshots?tab=logs&logId=view_log_id&from=2026-04-10&to=2026-04-10
open and select one exact row for copying; date-only from/to filters cover
full checked days. If the operator clears the focused selection, refreshes do
not reselect it unless the URL focuses a different logId.
The bridge applies the same acting-user boundaries as the DealDash website:
owned records are visible by user ID, team-shared deal logs require active team
membership and deal sharing, and screenshot previews are included only when the
acting user owns or can explicitly view the screenshot.
Use deals.create_view_log for completed LinkShot proof rows only after the
evidence packet or direct visual review confirms the source video URL,
screenshot id/short link, checked date, per-platform view count, direct 1xBet
proof, and screenshot sourceUrl matching the same canonical source video. Do
not use profile/channel/grid screenshots for a specific-video view log. If a
platform has no matching video, report no <platform> / no-video-found instead
of creating a zero-view or profile-only record. It routes to
POST /api/agent/deals/:id/views as a Tier 1 write and produces rows visible in
View Logs / extension-copy output. Use deals.bulk_add_view_checks instead for
unchecked source post/video links.
LinkShot Slash Workflow
When the user mentions a date and asks for screenshots or links if they already exist, parse first and browse later. Test this in the app at/tools/linkshot/settings. The operator runbook is
LinkShot Agent Workflow.
Supported aliases are /linkshot, /ls, and /dealdash-linkshot. Supported
date forms include may 22, may 21-23, 22 may, 22/05/2026, 22/05/26,
2026-05-22, today, yesterday, and tomorrow.
Expected sequence:
- Parse the command and remove instruction words such as
send,screenshots,links, andalready therefrom the query. - Expand the requested date by the local fallback setting, default one day before and one day after.
- Call
deals.view_logswithscope=mine-and-shared,from,to,q, andlimit. - If rows exist, send response-level
copyTextplus source/screenshot links. - If rows are missing, move to
deals.due_views,screenshots.list_latest, andlinkshot_evidenceplanning before browser work. - Capture proof only from the relevant post/video page, keep the highlight visible, prefer English pages, and require verifier acceptance before persistent writes.
Bulk Add LinkShot View Checks
Usedeals.bulk_add_view_checks when the user sends a bulk list of post links
and a post date. It routes to POST /api/agent/deals/bulk-import/process.
This is a logged Tier 1 operational write, so agents should run it directly
when asked to add video/post links for LinkShot view checking.
Input goes in params:
postDate: required, for example2026-04-13linksText: pasted links; blank lines separate people/groupscollections: structured alternative, each item hasurls, optionalpromoCode, optionalname, and optionaldealDetails(name,price,viewsTarget,promoLink,contact,notes)
created: videos added to matched owned deals or newly created owned dealsneedsPromoCode: grouped links that need a promo code before a deal/video can be createderrors: groups that failed validation or insertion
needsPromoCode is not empty, reply with those
links and ask for the missing promo code plus any available deal details. Each
item includes nextAction.agentPrompt, requiredFields, optionalFields, and
retryParams. Use that as the pipeline: collect promo/deal details, retry
bulk_add_view_checks with the same postDate and grouped urls, and DealDash
will create or reuse the owned deal and add the video to LinkShot view checking.
Team-shared deal matches remain read-only and are returned for promo-code
review. Direct standalone deal/payment writes and deletes still follow the
sensitive-write approval policy. If this endpoint returns approval_required,
treat it as a stale backend/policy deployment mismatch for this flow instead of
switching to generic deal create/update.
Context Search And Memory
Usecontext.search before guessing exact IDs. It searches deals, screenshots, LinkShot logs, short links, contacts, influencers, and active memory. Useful filters:
q: text queryscope:mineormine-and-sharedtypes: comma-separated list such asdeals,screenshots,view_logs,memorylimitandoffset
resourceUri, web link when available, access/ownership context, and metadata. Shared data still follows website sharing rules.
Use memory.create only after telling the user the exact title, content, tags, and source you will save. Memory is visible, account-scoped, and searchable through context.search.
Use memory.archive to remove stale memory from active context. Do not promise permanent deletion in V1.