Skip to content

dsh-roam-planner

Verified

dsh-roam-planner Β· v0.2.3 Β· MIT Β· Web UI

Trip planning workspace for DeepSeek Harness: map panel, itinerary store and Roam tools.

Install

dsh plugin add dsh-roam-planner

Confirm the layer applied with dsh --profile default --dump-config β€” see the install guide.

Source

Tags

Creators

Readme

dsh-roam-planner

Trip planning inside DeepSeek Harness: talk a plan into existence, watch it land on a map, and adopt it when it looks right.

The agent edits a draft. A candidate is frozen for review, and only an explicit Adopt commits it β€” so a hallucinated revision can never overwrite a plan you already accepted.

Requirements

  • DeepSeek Harness ^0.2.1-rc.2 (engines.dsh)
  • No extra services: no Docker, no database, no API key required

Install

plugin_manager install_bundle <this package or directory>

Then restart DSH: the host half loads its tools and /roam/api routes at startup. After the restart the sidebar shows a Roam Planner icon, and the agent gains the roam_* tools.

First run

  1. Click the sidebar icon β€” an empty panel says to ask the agent for a plan.

  2. In any conversation:

    Plan two relaxed days in Suzhou for me and my parents

  3. The agent calls roam_get_snapshot, roam_prepare_draft (place names only β€” the host geocodes them) and roam_fill_routes. The panel polls every few seconds and follows along.

  4. roam_save_candidate freezes the plan; a green Adopt plan button appears.

  5. Adopt it. Editing afterwards reopens a draft, and the panel shows what changed against the adopted version.

Optional: Amap key

Place lookup and routing work without a key (OpenStreetMap + OSRM), but Chinese addresses resolve far better through Amap.

Settings β†’ Roam Planner β†’ Amap Web-service key (not a JS API key). The key is written to the host credential store under ROAM_PLANNER_AMAP_KEY, is never sent back to the page, and takes effect on the next lookup β€” no restart.

Configuration

Everything below lives in the plugin row's config in cordis.patch.yml:

Key Default Meaning
basemapId osm Basemap selected on first use
basemaps null Replacement provider catalogue (array of {id, label, url, attribution, maxZoom, crs}); null uses the built-ins
geocoder nominatim nominatim, amap, or off
amapKey null Deployment-level key; a key saved in Settings wins
defaultCity null City appended to place names, e.g. θ‹ε·ž
dataDir null Directory for the JSON fallback store

External MCP sidecars (optional)

Railway tickets and Xiaohongshu notes are not built in. The plugin speaks MCP itself β€” stdio and streamable http β€” so any sidecar can be attached through config, and servers start on the first call rather than at activation.

The agent reaches them through roam_mcp_servers, roam_mcp_tools and roam_mcp_call.

Railway: use the bundled proxy

server/railway-mcp.js is our own MCP server in front of the third-party 12306 sidecar. It owns the railway business API, so the caller gets a time window, a station filter and a row cap instead of an entire day of trains:

Parameter Meaning
from_station, to_station, date The query itself (date = YYYY-MM-DD)
time_from, time_to Departure window, HH:MM
station Keep trains serving this station (a city has many)
limit Maximum trains returned, default 10, max 50
- id: roam-planner
  config:
    mcpServers:
      - name: railway
        command: node
        args: ['<plugin>/server/railway-mcp.js']
        env:
          RAILWAY_PYTHON: 'C:\...\python.exe'        # has mcp-server-12306 installed
          RAILWAY_PYTHONPATH: 'C:\...\site-packages'

A raw streamable http sidecar is configured with transport: http and url. Add command (plus optional args/env) and the bridge starts the process on first use, waits for the port and then speaks HTTP β€” nothing has to be launched by hand.

Sidecar Source Notes
12306 tickets drfccv/mcp-server-12306 The project states non-commercial use only
Xiaohongshu notes xpzouying/xiaohongshu-mcp Needs a one-time login; serves HTTP on :18060

Tools

Tool Effect
roam_get_snapshot Read the session trip (creates an empty draft if none)
roam_prepare_draft Apply a title/days change; stops need only a name
roam_save_candidate Freeze the draft for review
roam_adopt Commit the candidate
roam_fill_routes Fill missing leg geometry and durations (Amap or OSRM)
roam_forecast Daily weather at each day's first stop (read-only)
roam_search_places Keyword search for real places (needs an Amap key)
roam_mcp_servers / roam_mcp_tools / roam_mcp_call Reach an attached MCP sidecar

Data

  • Trips live in the DSH storage domain ($DSH_HOME/storages/roam_planner.json), falling back to <dataDir>/.roam/store.json when the domain is unavailable.
  • The Amap key lives in the credential store, never in the trip data.
  • The page remembers the chosen basemap locally; that is a viewing preference, not trip data.

Troubleshooting

Symptom Cause / fix
Panel says the host routes are unavailable The host half failed to activate β€” restart DSH
Map is blank but the day list renders Basemap tiles could not load (network or provider policy)
Routes are straight dashed lines No route source answered; fill them with roam_fill_routes
Weather chips missing The forecast has no data for those dates yet

License

MIT β€” see LICENSE. This is an independent implementation; see PROVENANCE.md for the boundary against the upstream project it was inspired by.