Documentation

Canvases and running services

A canvas is a drawing of the few services you are working on right now. What is on it is what runs.

Canvases

A canvas is drawn, not discovered: which three services out of forty matter today is yours to say. There can be many, each for a different piece of work.

  • Choose one from the picker in the header. Canvases are grouped by project.
  • Make one with + beside the picker (+ New canvas when there are none yet).
  • Rename or delete one with the ⓘ button, which opens Canvas details. Deleting a canvas removes the drawing only; the services themselves are not touched. A canvas cannot be deleted while its services run.

A canvas belongs to the project that was selected when it was made, and is saved with it under ~/.debugt. It can still hold services from several projects: drag from one project, select another in the left pane, and drag from that one too.

Putting services on a canvas

Drag a service from Services onto the canvas, or double-click it. The first time, Debugt asks What kind of service is this? — see APIs, event services and consumers.

Each node shows:

  • A state dot — stopped, starting, running or paused (on a breakpoint).
  • Its branch, above the node.
  • Its host, and a count of its overrides, below it.

The captions can be hidden from the canvas’s toolbar or its right-click menu (Hide branch, host and overrides).

A node whose project is not open in any VS Code window is drawn unresolved — dotted, in amber — and keeps its place and its lines until the project is opened again.

Running and stopping

The buttons in the canvas’s top-right corner act on the whole canvas:

Button Does
▶ Run all Starts every service on the canvas under the VS Code debugger, all at once. Muted ones are left out.
■ Stop all Ends every debug session the canvas started, all at once.
↻ Restart all Stops the running services, then starts them again.

Services start together, so a slow one — a Java service whose language server is still importing the workspace — holds none of the others back. Each turns green as it comes up, in whatever order that is. If one service needs another up before it can start, have it retry its connection.

Right-click a node for the same three on one service — Run, Stop, Restart — for the restart you want without disturbing the sessions around it. Select several nodes (Ctrl/Cmd-click, or Shift-drag a box) and right-click to act on the selection.

Things to know:

  • One canvas runs at a time. While one is running, another’s Run is disabled until you stop the first or switch back to it.
  • An API service needs a host before it can run. Run all tells you which ones are missing it.
  • One failing does not stop the rest. The failures are named in a message over the canvas.
  • A service started with F5 shows as running on the canvas and can be stopped from there.
  • Starting means the debugger has attached; running means the service is really up. See When a service is “running”.

The node menu

Right-click a node:

Item Key Does
Run, Stop, Restart R, S, ⇧R Act on this one service.
Mute / Unmute M A muted service stays on the drawing but is left out of Run all, and any redirect on its lines is held off.
Details ↵ Opens the service’s window — below. Also opened by double-clicking the node.
Add request N Creates a saved request for this service and opens it in the runner.
Show Requests Finds this service’s requests in the left pane, or says it has none yet.
Open in VS Code O Shows the service’s file in the VS Code window that has it open — below.
Remove from canvas Delete Takes it off this canvas. The service and its requests are untouched.
Point this node at… Shown when its launch configuration is gone: pick what it is called now.

The menu lists only what applies: no Run on a running service, no Stop on a stopped one. A service paused on a breakpoint counts as running. An item that applies but cannot be used now — an API with no host, a muted service, another canvas running — is greyed, and says why when you hover it. A node whose repo is not open in any VS Code window shows one note in place of the items it cannot do.

Open in VS Code opens the file that is the service, trying in turn: an event service’s handler, at the function it calls; the launch configuration’s program; a Python module of the service’s own, or the app it serves (flask --app, uvicorn main:app); the service’s folder, in the explorer; and last, launch.json.

The canvas menu

Right-click the canvas itself, away from any node:

Item Does
Run all, Stop all, Restart all As the buttons — R, S and ⇧R.
Restart all edited Restarts only the services marked edited.
Restart all switched Restarts only the services whose branch changed since they started.
Restart all with changed overrides Restarts only the services running without an override they need a restart for.
Restart all with changed environment Restarts only the services whose environment profile changed since they started.
Environments… The project’s environment profiles.
Override Libraries… Every open project’s override library.
Hide branch, host and overrides Hides the captions under and above the nodes — H.

Each Restart all… is listed only while it would restart something; the rest keep running.

Keys

The key beside a menu item works while the menu is open. With nothing selected and no menu open, R, S and ⇧R are Run all, Stop all and Restart all, and H hides or shows the captions. Any key on the canvas closes a menu that is open.

Read-only while running

While any service on a canvas is running, the canvas is read-only: nodes do not drag, lines cannot be drawn or removed, and details open for reading. A lock shows beside the canvas’s name. The rules went into those processes when they started, so an edit now would look applied and would not be until a restart.

Run, Stop, adding a request, panning and selecting all still work. A service’s overrides can still be changed, and are used from its next call. Its environment and redaction can be changed too, and apply from its next start.

Edited and switched

Two marks tell you that a running service may no longer be running the code you are looking at.

edited appears under a node once a file in the service’s folder no longer holds what it did when the service started. Click it to open Edited files, which lists them; each opens in VS Code, and Restart service restarts it on the code as it is now. Files git ignores do not count, nor a file saved again unchanged, nor a binary file or a debugger’s build (__debug_bin…), and an edit put back takes the mark off. A program that is a folder, such as a Go package, is watched as that folder. This can be switched off in Settings → General.

A branch change shows in the branch caption as started-on → current when the checkout has moved to another branch since the service started.

The canvas menu then offers Restart all edited and Restart all switched, for just those services; the rest keep running.

Redirects

A line between two nodes is a redirect: when the source service calls the remote it would normally reach, send that call to the target running on your machine instead.

Draw a line from one node to another and the New redirect dialog asks what it means:

  • When source sends to — the method (or ANY) and the address the service calls today, such as https://api.example.com. It is matched as a prefix: the rest of the path and the query are carried across.
  • Redirect to target — the target’s host, with an optional path.
  • Redirect active — untick to send calls to the real address while keeping the rule.

A service may reach the other at more than one address — https://inventory.example.com and an older https://legacy-stock.example.com/api. + Add another call adds one to the same line, each with its own path on the target and its own On switch; Remove takes one off. The line’s own checkbox still turns all of them off together.

Double-click a line to change it. Right-click a line to Edit redirect…, Turn redirect off or Remove line. A line moves while both its services run and a redirect on it is on; dashed, it carries nothing.

Things to know:

  • Rules are applied when a service starts. Change one, then restart the source.
  • Each redirected call prints a line in the Debug Console. A request going somewhere other than where the code says is never silent.
  • One call can only go to one place. A call that another line out of the same service — or a call above it on the same line — already claims is refused. Where prefixes overlap, the more specific rule wins, and on the same address a rule for one method wins over an ANY one, whichever was drawn first.
  • localhost, 127.0.0.1 and ::1 are treated as the same host.
  • Redirects are applied to Node, Python, Java and Go services. See Language support and limits.

A line into an event service is a trigger rather than a redirect, and nothing can be drawn into a consumer: see APIs, event services and consumers.

A service’s window

Double-click a node, or choose Details from its menu. Everything about the service is in one window, its sections listed down the left with what each holds beside it:

Section Holds
Details Its kind, host and the rest — below.
Function overrides, URL overrides What it is answered with instead of the real thing — Overrides.
Environment The environment profile it starts with — Environments.
Redaction Recorded variables it redacts beyond its project’s list — Settings → Redact.

Each section keeps its own way of saving: Details on Save, overrides as each is made, an environment profile on its Save. Something left unsaved in any of them is asked about once, as the window closes, and a dot marks the section it is in.

Details

Field Meaning
Name The launch configuration’s name. Changed in launch.json, not here.
Kind API service, Event service or Consumer. Change to pick another.
Host For an API: where its requests are sent, and where a redirect into it points. A localhost port is also handed to the service as PORT. Debugt warns if another service already has that port, or something is listening on it now.
It has no port For an API that listens on nothing.
Ready pattern A regular expression matched against the service’s output. Until a line matches, the service shows as starting.
Handler, Triggers For an event service.
Protocol For a consumer: what it takes its messages off.

While the service runs, Details is read-only: stop it to change these. Its overrides, environment and redaction can still be changed.

Overrides

An override answers something the service calls with a value you set: a library function, or a URL. Use one to make the payment gateway decline, the clock say it is midnight, or a partner’s API answer 503.

A service’s overrides are two sections of its window: Function overrides and URL overrides. Open them from there, or from the overrides count under the node. The count turns red when something is wrong: a library that is not open, an entry that is gone, or an override the running service needs a restart for.

Each tab has two halves: This service only, the service’s own, and From project libraries, entries it uses from a library. A change is saved as you make it. Each row has a ⋯ menu — also on right-click — to Edit it, Clone it, Disable or Enable it without losing it, or remove it.

One value per call at a time. Only one of a service’s own overrides for the same call — the same verb and URL, or the same module and function — can be on. Keep the others as values to switch between: Clone adds a copy switched off, and ticking a row’s box switches off any other for the same call. A row left on below another for the same call answers nothing, and is marked not answering.

Function overrides

On the Functions tab, choose + Add override. Under When the service calls:

  • Module — as the service imports it: a package (somelib), a file in the service (./src/lib/pay.js), or a dotted Python module (app.clients.pay).
  • Function — someFunction, Client.prototype.send for a method, or default for the module’s default export. A module written as module.exports = fn is that one function: name it default.

Under Answer with:

  • Replace — never calls the real function; every call returns your value.
  • Merge — calls the real function and deep-merges your value into what it returns.
  • Value (JSON).

Overrides apply to every call the service’s own code makes. A call the library makes to its own function from inside itself is not overridden. They work in Node and Python services.

Things to know:

  • A relative path is read from the service’s folder — its launch configuration’s cwd — not from the file that requires it. If src/jobs/fetch.js requires ./parse-rows, the override names ./src/jobs/parse-rows. If no file is there, the Debug Console says so as the service starts, and suggests the path you may have meant. Nothing is overridden.

URL overrides

A URL override answers a call the service makes — by verb and URL — with a status, headers and body you set. The call never leaves your machine.

On the URLs tab, choose + Add URL override and give the Verb (one, or Every verb), the URL the service calls, the Status, and a Response body (None, JSON, Text or XML). Every call to that address, and to anything under it, is answered there.

  • Where URLs overlap, the longest one wins, whatever their order: an override for https://api.example.com and one for https://api.example.com/v1/orders can both be on, and calls to /v1/orders get the second. On the same URL, an override for one verb wins over an Every verb one, whatever their order.
  • Only one override for the same verb and URL is on at a time — see One value per call.
  • An answered call still shows in the trace, as the call the service made, marked override.

While the service runs

A change to a running service’s overrides is saved as you make it and used from its next call — no restart. That covers a value changed, an override switched on or off, one removed, and any URL override, added or changed; a library entry it uses, edited, reaches it the same way.

One thing needs a restart: a function the service did not start with an override for. The window says which, and Restart puts it in place; until then the rest are in use. The canvas menu’s Restart all with changed overrides does the same for every service waiting on one.

A save that takes more than a moment says Saving….

Override libraries

An override worth keeping can be kept in a library: named overrides that belong to a project, for any service on any canvas to use. Open them from Override Libraries… in the canvas menu, which opens on the canvas’s own project. Each project has its own, saved under ~/.debugt in projects/<project>/overrides.json.

  • Using one. In a service’s Overrides, choose + Attach from a library. Entries from every open project’s library can be attached, and they are listed under From project libraries.
  • Linked, not copied. An attached entry stays the library’s. Edit in library changes it for every service that uses it; if that is more than one, Debugt asks Change it everywhere?, with Save for all or Save as new entry. Make a copy gives the service a copy of its own, which library edits no longer change.
  • Moving one in. Move to library on one of the service’s own overrides moves it into a library, by name.
  • Several values for one call. A library can hold as many entries for the same call as you like — Login ok, Login expired, Login 500 — for each service to attach the one it needs. Clone on an entry adds a copy under a name of its own: Login ok copy.
  • Off for one service. Disable on an attached entry switches it off for that service only; the library is not changed.
  • Removing an attached entry takes it off the service. It stays in the library.

Things to know:

  • The service’s own override wins over an attached one that answers the same call, and an entry attached earlier wins over one attached later.
  • A library names packages, not paths. A function override in a library must name a package, a builtin (node:fs) or a dotted Python module. One that names a file by path, relative or in full, is refused there: a relative path would be read from each service’s own folder, and a full one is this machine’s alone. It stays on the service — Move to library is not offered for it, and + Attach from a library leaves such entries out. An older library entry that names a path is kept, marked Not usable: a path, and not applied on the services that use it, which say why.
  • On the Free plan, a library holds up to 5 overrides in each project, functions and URLs together; Pro has no limit. Override Libraries shows how full each one is — 3 of 5. The limit is checked only as an override is added to a library — by + Add override, + Add URL override, Move to library or Save as new entry — and a full library says so in place of the way to add one. One already kept is still edited, attached and applied, whatever the plan. A service’s own overrides have no limit.
  • A library that cannot be read stops the service starting, rather than run it with calls answered by the real thing. Open the project that holds the library, or remove the entry.

Environments

An environment profile is a named set of variables a service can start with — Local, Staging, a teammate’s database — so switching where a service points is a choice and a restart, not an edit to launch.json.

  • Make them in Environments…, in the canvas menu. A profile belongs to a project, and is written as a .env file is: KEY=value, one to a line — paste one in whole. These are its shared variables, for every service of the project that uses it.
  • Choose one for a service in its window’s Environment section: each of the project’s profiles is a tab, and Use Staging for orders sets the one it starts with. Stop using it goes back to launch.json’s env alone.
  • A service’s own variables, set in the same tab, go over the profile’s shared ones for that service alone — its own PORT or queue name. A shared variable it overrides is struck through.

As a service starts, its profile is merged over the env in its launch configuration — its own variables over the shared ones — in every language Debugt runs. Variables Debugt sets itself, DEBUGT_ and the like, cannot be changed by a profile.

A profile changed while a service runs with it applies from its next start: the service says Restart to apply, and the canvas menu offers Restart all with changed environment. A profile in use is named before it can be deleted.

Profiles are kept on this machine only, in ~/.debugt, never in a repository — so a staging password in one stays on your machine. See Where your data is kept.

The canvas console

At the bottom-left of the canvas: a running log of services starting, stopping and coming up, and each send as it comes back. Type in its box to keep only the lines with every word you type — a service’s name, error, a trace id — with the words marked; Escape clears it. Click a send’s line to open its trace. Drag its top edge, its right edge, or its top-right corner to resize it both ways at once; double-click an edge to put it back. Its font size and background are in Settings → Console.

Several VS Code windows

Each VS Code window can only drive the debugger for the folders it has open. So the windows connect to each other: the first one opened serves Debugt’s page, and the others register their projects with it. The header shows how many windows are connected.

A service is always started in the window that has its project open, which is where its breakpoints are hit. If the window serving the page closes, another takes over at the same address and the page reconnects on its own.

After updating Debugt, reload any VS Code window left open from before: a window still on the older version is turned away with a message asking for that.