Skip to content
dsh.fish
Bundle

dsh-loop

DeepSeek Harness plugin: a /loop slash command for timed recurring agent loops

Source
XiaoWind
stars
1 stars
License
MIT
Updated
Updated 23 hours ago

Readme

# dsh-loop

English | [中文](README.zh.md)

A [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH)
plugin that adds a human-facing `/loop` slash command for **timed, recurring
agent loops**.

`/loop 30m` fires one immediate tick, then re-prompts the agent once per
30-minute interval (measured from the moment the agent returns to idle after
the previous tick) until you stop it with `/loop stop`.

## Install

```sh
# from GitHub (works immediately — no npm publish required)
dsh plugin --profile web add git+https://github.com/XiaoWind/dsh-loop.git

# or from npm, once published
dsh plugin --profile web add dsh-loop
```

The `dsh plugin` command forwards to `pnpm` inside the `web` profile directory,
then reconciles the profile's `dsh.profile.bundles` layer list. Because this
package declares `dsh.bundle.patch`, it joins the layer stack automatically.
Restart the Web app after installing.

> The plugin injects the `commands` service, so it activates only in profiles
> that compose a command adapter — the shipped `web` profile does.

## Update

Pull the latest version of the plugin into an installed profile:

```sh
dsh plugin --profile web update dsh-loop
```

`dsh plugin` forwards to `pnpm update dsh-loop` inside the profile directory,
which re-resolves the `github:XiaoWind/dsh-loop` dependency to the latest commit
on the default branch. The lockfile pins a git dependency by commit hash, so a
`version` bump is not required for the update to land. If pnpm has cached an old
git resolution, re-pin it explicitly:

```sh
dsh plugin --profile web add github:XiaoWind/dsh-loop
```

Restart the Web app after updating — the bundle layer is composed at boot, so a
running Web process does not hot-reload an installed plugin.

## Usage

| Command | Result |
|---|---|
| `/loop 30m` | Start a loop: tick now, then once every 30 minutes. Keeps any current objective. |
| `/loop 30m fix the tests` | Start a 30-minute loop toward an objective. |
| `/loop fix the tests` | Start a loop toward an objective at the default interval. |
| `/loop 1h30m` | Combined durations are supported. |
| `/loop resume` | Resume the loop saved before a restart. |
| `/loop` or `/loop status` | Show the running loop. |
| `/loop stop` | Stop the loop. |
| `/loop help` | Show help. |

Intervals are a whitespace-free sequence of `<number><unit>` tokens where
`unit` is one of `ms`, `s`, `m`, `h`, `d` — for example `90s`, `30m`, `1h30m`,
`2h`.

A leading duration token is the interval and the remainder is the objective;
with no leading duration, the whole input is the objective and the default
interval applies.

### Semantics

- **First tick is immediate.** Each later tick fires `interval` after the agent
  returns to idle, so a running turn is never interrupted.
- **Saved across restarts.** The loop config is persisted to
  `$DSH_HOME/dsh-loop/<sessionId>.json`. When you reopen the session after a
  restart, the plugin asks whether to continue the saved loop (`Continue` /
  `Stop`); `/loop resume` restarts it manually when no prompt is available.
  `/loop stop` discards the saved loop.
- **Manual stop.** The loop runs until you run `/loop stop`, the agent is
  disposed, or the plugin is unloaded. There is no automatic completion
  detection.

## Configuration

Set `config.defaultIntervalMs` (milliseconds) to change the interval used by a
bare `/loop <objective>` with no leading duration token. The default is
`600000` (10 minutes).

```yaml
# your profile's cordis.patch.yml
- id: loop
  config:
    defaultIntervalMs: 900000
```

## Development

```sh
# syntax check
node --check lib/index.js
```

The plugin is a single-file ESM Cordis function plugin (`lib/index.js`) with no
build step. It exports `apply`, `inject`, and `name`, and the bundle layer
`cordis.patch.yml` inserts it into the profile composition.

## License

MIT

Install

dsh plugin --profile web add github:XiaoWind/dsh-loop

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source