Early access Backcast Labs is not on sale yet. The research notebook runs in your browser on simulated data. Join early access
Documentation

From install to a signed export

Code samples are Python 3.12 against the planned engine API. Backcast Labs is in early access: this documentation describes the product as designed and can change before release.

1 · Getting started

1.1 Install & activate

Downloads open with early access. Installation instructions will be published here together with the first builds. Until then, everything in the next sections can be tried in the notebook demo on simulated data.

1.2 Your first honest run

Open Strategies → EMA trend-following, leave the defaults (slippage 20 bps, commission 5 bps, next-bar fills, delisted symbols included) and press Run. Then, in this order:

  1. Read the Drawdown panel before the equity curve. If the maximum drawdown is beyond your halt (−20 %), the strategy would have been switched off live.
  2. Open Walk-Forward. An efficiency ratio below 0.5 means the parameters were fitted, not found.
  3. Open Monte Carlo at 1,000 paths. Note P5 and the probability of a −20 % drawdown.
  4. Only now look at CAGR and Sharpe. The Deflated Sharpe row accounts for how many parameter combinations you tried.

1.3 Strategy templates

Table 1. Bundled strategy templates.
TemplateUniverseFree parametersNotes
EMA trend-followingBTC, ETH, SOL · 4hfast, slow, ATR stopLong/flat. A good first walk-forward exercise.
Cross-sectional momentum18 crypto perps · weeklylookback, top-kLong top-k / short bottom-k, beta-neutral. Uses portfolio-level slippage.
Mean-reversion pairsETH/BTC, SOL/AVAX, LINK/DOTz-entry, z-exit, windowHedged. Sensitive to borrow costs.
Macro regime switchSPX, gold, BTC, TLT · monthlyliquidity threshold, risk thresholdNeeds the €49 macro pack.
Breakout + ATR stopCommodity futures · dailychannel, ATR multipleContinuous contracts with roll adjustment from the commodities pack.
Imported signal stackBTC, ETH · 4has declared by the importFour filters stacked on one book. Robustness 0.22 — the weakest template bundled, and shipped because you should see one. See §6.2.

2 · Engine

2.1 Event loop & fills

The engine iterates bars in time order and calls on_bar(ctx) once per bar per strategy. ctx.data exposes only bars with a timestamp at or before the current bar's close. Orders submitted during on_bar are queued and filled on the next bar according to the fill model:

Table 2. Fill models.
Fill modelFill priceUse
next_open (default)next bar open ± slippageRealistic for bar-close signals
vwapnext bar VWAP ± slippageOrders worked over the bar
worstworst price of the next barStress test; stops fill at the bar extreme
tickwalks the tick tape with impactRequires a tick-level pack

Any attempt to read a future bar raises LookaheadError. Every report embeds the engine build hash and the config hash, so a result reproduces exactly on the same version.

2.2 The notebook format

A strategy here is a notebook: one .fnb file holding a Strategy subclass — its param() declarations and one on_bar(ctx) — written in plain Python against the engine API. That is the only strategy format this product has. The notebook is what the engine runs, what the walk-forward sweeps, what the search counter counts and what the export signs. There is no second language to learn and nothing is transpiled behind your back.

from forge.strategy import Strategy, param

class EmaTrend(Strategy):
    fast = param(20, min=5, max=60, step=5)
    slow = param(50, min=30, max=200, step=10)
    atr_mult = param(2.5, min=1.0, max=5.0, step=0.1)

    def on_bar(self, ctx):
        c = ctx.data.close                      # only bars <= now
        if len(c) < self.slow + 1:
            return
        fast, slow = ctx.ind.ema(c, self.fast), ctx.ind.ema(c, self.slow)
        atr = ctx.ind.atr(ctx.data, 14)
        if fast[-1] > slow[-1] and not ctx.position:
            ctx.order_target_pct(0.25 * ctx.kelly_fraction())   # Kelly 0.25 sizing
            ctx.stop_loss(c[-1] - self.atr_mult * atr[-1])
        elif fast[-1] < slow[-1] and ctx.position:
            ctx.close()

param() declarations are what the walk-forward optimizer sweeps. Everything else is plain Python; pandas and numpy are available inside on_bar for research, though the vectorized helpers in ctx.ind are faster.

2.3 Cost model

costs:
  slippage:   { model: fixed_bps, bps: 20 }      # or spread_k / participation
  commission: { maker_bps: 2, taker_bps: 5 }
  funding:    { source: pack }                   # perps: 8h funding from the data pack
  borrow:     { source: pack, fallback_apr: 0.08 }
  portfolio_level: true                          # v1.8.1: aggregate same-bar legs

Run Analyze → Sensitivity to sweep slippage 0–50 bps and see where the Sharpe crosses 1.0. See WP 2026-07-30 for choosing a number.

3 · Validation methodology

3.1 Overview

A single in-sample backtest is a hypothesis, not evidence. The validation stack, in the order we recommend running it:

Table 3. Validation stack and default pass criteria.
StepQuestion it answersPass criterion (default)
In-sample / out-of-sample splitDoes the edge exist outside the fitting window?OOS Sharpe > 0.5 × IS Sharpe
Walk-forward (6 folds)Are the parameters stable through time?η ≥ 0.5; at least 4 of 6 folds profitable OOS
Monte Carlo (1,000 paths)What does luck look like?P(DD ≤ −20 % in 12 m) < 10 %
Deflated SharpeIs the result explained by the number of trials?DSR > 0.95 probability
Worst-of-bar stressDoes it survive a liquidity vacuum?Max DD within the halt

In-sample / out-of-sample. The simplest split: fit on the first 70 %, test on the last 30 %. Its weakness is that you get one out-of-sample number and it depends on which 30 % you chose. Walk-forward fixes this by repeating the split.

3.2 Walk-forward: anchored vs rolling

Anchored: the in-sample start is fixed at the beginning of history and the window grows each fold. Prefer it for structural, low-frequency edges. Rolling: a fixed in-sample length sliding forward. Prefer it for adaptive, higher-frequency edges. Run both; a large discrepancy means the strategy is sensitive to memory length.

validation:
  walkforward:
    mode: rolling            # rolling | anchored
    folds: 6
    in_sample: 0.70
    objective: sharpe        # sharpe | calmar | robust (plateau-weighted)
    min_oos_trades: 30       # warn if a fold has fewer

Output: a per-fold table (IS Sharpe, OOS Sharpe, OOS return, chosen parameters), the stitched out-of-sample equity curve, and the efficiency ratio η = mean(OOS Sharpe) / mean(IS Sharpe). The export button is disabled below 0.5 until you acknowledge the warning.

3.3 Monte Carlo resampling

Three resampling methods on the trade sequence: plain bootstrap (draw trades with replacement), block bootstrap (draw blocks of consecutive trades, preserving regime clustering — recommended for crypto), and stationary bootstrap (random block lengths). Each path respects the drawdown halt: once a path breaches −20 %, it stops trading, as production would.

validation:
  montecarlo:
    paths: 1000
    method: block            # plain | block | stationary
    block_size: 20
    horizon_days: 252
    dd_halt: -0.20

Reported: P5 / P50 / P95 terminal equity, the maximum-drawdown distribution, and the probability of breaching the halt within the horizon. Read the P5, not the P50.

3.4 Deflated Sharpe ratio

After Bailey & López de Prado (2014). The deflated Sharpe adjusts the observed Sharpe for the number of independent trials N, the variance of Sharpe across trials, the skew and kurtosis of returns, and the sample length. Backcast Labs counts N automatically from the parameter grid you actually evaluated, including walk-forward folds, so you cannot forget the 9,999 combinations that lost. A probability above 0.95 means the Sharpe is unlikely to be a selection artefact.

DSR = Φ(SR − SR₀) · √(T − 1)√(1 − γ₃ SR + ¼(γ₄ − 1) SR²)(1)

4 · The quant reviewer

4.1 What it does

The reviewer is one agent reached from three places: the key in every cell rail (pre-scoped to that cell), the AI Analyst card above the sheet, and the command palette. It has two registers. Asked: you send it one of six questions and it executes a plan against the same engine functions the panels use — running cells, pricing counterfactuals, narrating each step with the number that step produced, and ending in a verdict. Unasked: you give it a standing mandate once and it re-checks on the clock and on every state change, writing what it found into the research log.

Separately, the AI Explainer is on by default and rewrites itself out of every run in plain language. It is a reader, not an actor — it never runs a cell and never changes a parameter.

It acts, it does not describe. Every reply ends with a line stating what it just did. When it could not do something it says so: “The engine is mid-run. I will not stack a second backtest on top of it — ask me again when the run lands.”

4.2 The six plans

Each plan is a fixed sequence of steps. Nothing is improvised, so two runs on the same state produce the same work.

Table 4. The six questions the reviewer will go and answer, and what each one runs.
QuestionWhat it runs
Is this a real edge, or did I search until it looked good?Counts the session's configurations, sweeps the 49-square neighbourhood, races 400 matched random entries, cuts six walk-forward folds, re-prices at 1 bp a side.
Is it better than luck?400 random entries with your exact trade count and holding period, the luckiest of those 400, buy-and-hold on the same window, and the noise bar for how much you have looked.
Does it survive its costs?Prices the same parameters at 1 bp and at 45 bps a side, reads the data-quality report, then walks slippage from 25 to 50 bps until the result stops standing up.
Which parameter actually matters?Moves each of the four one at a time — lookback ±20 bars, ATR ±0.6× — and ranks the spreads against the standard error of a Sharpe on this sample.
Where does it break?Walks slippage, takes the lookback to both ends of its range, cuts the sample to the short window and flips the delisted names, then names the first thing that broke and your margin against it.
Can I make it more robust?Finds the maximin square — the one whose worst neighbour is the best worst neighbour on the grid — and prices it against the square you are standing on.

Verdicts are three-valued and the reviewer is willing to use all three. On the guest notebook's default run, asking the first question returns: “Not yet. It clears the noise bar, but not every check agrees … confidence: medium · 4 of 5 checks pass.” When a result is dead it says so and refuses to prescribe: “I am not going to suggest a parameter that fixes this, because there is no parameter that fixes this. The recommended action is to stop.”

It also refuses to rank two results it cannot separate — if the gap between two configurations is inside the standard error, it says “I will not rank them” and gives the error band instead.

4.3 Standing mandates

One sentence, said once, from four options. After that the reviewer works without being asked, on a scheduled check and on every state change.

Table 5. The four standing mandates and what each one watches.
MandateWhat it watches
“Tell me when something I am running stops being an edge.”The noise bar against your Sharpe, the deflated Sharpe through its 90 % and 80 % floors, walk-forward efficiency through 0.5, the random-entry percentile through the median, the drawdown against the −20 % halt, and the profit factor through 1.0.
“Keep watching my search count.”The configuration count and the bar it moves — it speaks each time you cross another ten configurations, with the new noise bar against your result.
“Re-validate anything I adopt.”Every configuration change: whether the new setting still clears its noise bar, its deflated Sharpe, and a re-price at double your slippage. That re-price is a configuration and is counted.
“Only speak when something actually breaks.”The drawdown halt, the cost model and the trade count. The quietest mandate here.

Every check writes a row into the research log in cell [12] under a second register, tagged with the mandate, with four columns: what it checked, what it found, what it did, and how many consecutive checks returned that same answer. Rows are exportable as CSV. A check that finds the same nothing as the last one is folded into the previous row with a count rather than repeated — filling a record with identical lines is not transparency.

It reports that nothing happened. The most common entry reads: “nothing crossed. Sharpe 1.09 against a noise bar of 0.83, deflated 76.7 %, drawdown −23.3 %, walk-forward efficiency 0.52.” — and in the “what it did” column: “Nothing. That is the answer most of the time, and I would rather say it than manufacture a finding.”

4.4 What its work costs you

This is the part most tools do not implement, so read it before you rely on the agent. Every configuration the reviewer prices is counted against your multiple-testing bar, exactly like one you set by hand. It is written into the research log with a via tag naming who ran it, and the deflated Sharpe in cell [7] falls accordingly.

Worked example, on the guest notebook's default run. Before you ask anything, cell [7] reads 49 distinct configurations · noise bar 0.83 · deflated Sharpe 76.9 %. Ask “is this a real edge?” and the plan's final step re-prices your parameters at 1 bp a side. That is configuration #50. Cell [7] now reads 50 distinct configurations · noise bar 0.83 · deflated Sharpe 76.7 %.

Configurations counted4950
Deflated Sharpe76.9 %76.7 %
Noise bar0.83
Your Sharpe1.09

The reviewer states this before it starts rather than after. Choosing “I have a strategy and I want to know if it is real” at the onboarding question prints, under What it costs you: “Validation spends the one budget you cannot get back: the Analyst prices six configurations to answer this, and every one of them lifts the noise bar the result has to clear. By the time it answers you, the bar is higher than it was when you asked. That is the honest arithmetic — and it is why the answer here is often no.”

Undoing a standing-review action restores the parameter it changed but does not un-count what it priced. The log says so explicitly: what stays: a configuration it already priced cannot be un-counted.

4.5 What it refuses

  • It will not move a parameter you set. Where it wants one moved it asks, and the ask appears as “wants a decision” on its card. The log column reads: “Reported it and stopped. I do not move a parameter you set.”
  • It will not size above quarter-Kelly and it will not model leverage. Asked to, it answers: “No. I will not go looking for a way to size this above quarter-Kelly, and I will not model leverage. Kelly 0.25 with a 7.5 % ceiling per asset and a −20 % halt is why the drawdown number on this page is survivable. The honest levers are a longer sample, uncorrelated sleeves and lower costs.”
  • It will not put a number on what this returns — not monthly, not annually, not as a range. It offers the shape of the bad draws instead: the Monte Carlo cell's probability of a −20 % drawdown inside twelve months, and the worst the sample actually delivered.
  • It will not research a holding period the cost model cannot support. The shortest average hold in the templates is under two days; at higher turnover the 20 bps round-trip model eats the whole edge before the first fill, and it says so instead of running it.
  • It will not plan on a disowned result. If the last run failed, it stops: “I will not build a plan on numbers the engine has disowned — fix cell [1] and I will pick this up again.” If the engine is mid-run it waits rather than stacking work on top.

Refusals are stamped refused on the panel and logged as a warning line, so a refusal enters the record rather than being a dead end you have to remember.

4.6 Pause, undo and stop

  • Pause / resume — one click on the standing-review card. Paused, it makes no checks and prices nothing.
  • Undo the last thing it did — one click, on the entry that did it. It restores what it changed and says in the log what cannot be restored.
  • Change the mandate — one click returns you to the four options; its baseline resets and the next check starts fresh.
  • Switch it off — the toggle on the card. The log line reads standing review off — nothing is being watched, so the record shows when it stopped.
  • Switch the Analyst off — its own toggle. A plan in flight is abandoned; nothing half-finished is written as a verdict.

4.7 Where its numbers come from

The reviewer never computes a figure of its own. Every number it quotes comes from the same function that draws the corresponding panel, so the assistant and the screen cannot disagree. When it runs a cell it reads what that cell just wrote, not a cached guess; when it prices a counterfactual it calls the engine with an override and logs the result. If it cannot compute something it names the panel that can, rather than estimating.

Everything on this page can be checked against the free guest notebook — its default run is the one every figure in §4.4 comes from.

4.8 The AI Automation Researcher

The reviewer works when you ask it. The researcher does not wait. Open it from the AI Automation Researcher control on the standing bar above the sheet, or press N. A six-question wizard composes an assignment; saving it starts a schedule that runs on the notebook's own clock until its budget is spent.

The wizard asks for a risk profile (the same six the notebook uses — there is no second risk scale), a direction (long only, or long and short: the two market-neutral books are unavailable one-sided, so this answer changes the size of the search), a timeframe or permission to choose one, the edge families it may try, and a budget in configurations. Each answer prints what it costs before you take it. The last step shows the house limits as fixed text with no control beside them, and the review step prints what I will do, why, what it will cost you, and what it will never do before anything is priced.

There is no unlimited budget. The wizard says why: an agent that can search without a ceiling is a strategy-mining machine — it will always find something, and the something it finds will always be worth less than it looks.

Each cycle takes one candidate through eight steps, every one logged with what it did, why, and the number it produced:

  1. Build the candidate — family, lookback and stop width, rotated breadth-first. Charges nothing: nothing has been evaluated yet.
  2. Run itcompute(), the same engine cell [1] runs. 1 configuration (3 if it is choosing the timeframe, because it prices all three).
  3. Price the cost model — at 1 bp a side and at 45 bps a side. 2 configurations.
  4. Sweep the neighbourhood — the eight settings one step either side, using the same grid arithmetic cell [5] draws, so an adopted candidate paints the same surface. 8 configurations.
  5. Race 400 random entries with its own trade count, holding period and exposure. No configuration: the random books are draws from the benchmark, not settings of this notebook.
  6. Cut six walk-forward folds — efficiency η and the mean Sharpe the out-of-sample windows printed. No configuration, and not free: a fold you have tested on is no longer untouched data.
  7. Resample 1,000 twelve-month paths and report the share that touch the −20 % halt.
  8. Report — six checks and a verdict, including reporting that it found nothing.

So a cycle costs 11 configurations, or 13 when the researcher is choosing the timeframe. A repeat of a configuration already evaluated costs nothing more, because the multiple-testing bar only moves for a setting nobody had tried — the agent reports both numbers, evaluated and spent, and it is spent that the counter moves by.

The six checks, all of them read from functions the panels use: clears the best-of-N noise bar · deflated Sharpe at least 90 % · beats 95 % of 400 random entries · still clears the noise bar at 45 bps a side · walk-forward efficiency at least 0.60 over six folds · sits on a plateau or a ridge rather than a spike. Three of those move with the configuration counter, so the checks are re-read every time the list is drawn: a candidate that cleared all six at 54 configurations comes off the shortlist when it stops clearing them at 400, and the list says which one fell and why.

Ranking. The results list does not default to raw Sharpe. Raw Sharpe is measured in sample, on the data the setting was chosen on, and it rises with how hard you looked. The default measure is the mean Sharpe the six walk-forward folds printed out of sample, minus the Sharpe a no-edge strategy would have been expected to print as the best of the configurations already evaluated when that candidate turned up. You can switch the sort to raw Sharpe; the list says in words that this is the ranking the product exists to argue against.

Alongside the ranked list: what survived (the shortlist that still clears every check right now, with the ones that have fallen off named underneath) and what it got wrong — candidates that cleared the noise bar and beat the coin flips and then broke on the folds or turned out to be a spike. That list is reachable in one click and is never pruned.

Worked example, on the guest notebook. Assignment: trend and mean reversion, long and short, 4h bars, sceptic profile, 80-configuration ceiling. Cell [7] read 49 distinct configurations · noise bar 0.83 · deflated Sharpe 76.9 % when it started. It built ten candidates, evaluated 110 configurations of which 38 had already been tried, and stopped because the next cycle needed up to 11 more than the 8 it had left.

Configurations counted49121
Reported spent by the agent72
Deflated Sharpe76.9 %65.8 %
Noise bar0.830.95

121 − 49 = 72, which is what the agent reports. Cell [7] breaks it out: 1 by hand · 48 from the sweep · 72 from the researcher. Your own Sharpe did not move; only its believability did.

Controls. Pause, resume, undo the last candidate, change the assignment, stop it and delete it are one click each. Undo does not refund the budget and does not move the counter back — the log says so: unseeing a result is not the same as not having looked at it. Deleting an assignment removes the record, not the spend. Assignments are remembered in this browser; their spend is not, because the counter starts again on a reload, so a restored assignment comes back stopped and says why.

The library. The researcher draws on fourteen named estimators and tests — Sharpe, Sortino, profit factor, Calmar, maximum drawdown and its path, skewness and kurtosis, the expected maximum Sharpe under the null, the deflated Sharpe, the Gaussian tail approximation, a 400-draw random-entry permutation test, walk-forward efficiency, a 1,000-path Monte Carlo resample, a maximin plateau search, and the cost-model decomposition — each naming the function that computes it, what it assumes and where it fails. Nothing is listed that this page cannot compute. The dataset list is the same one the settings surface writes, each entry stating its coverage and what it does not contain; every candidate names the dataset it was measured on.

5 · Data & keys

5.1 Exchange & broker keys

Add read-only API keys under Data → Sources. Planned: major crypto exchanges, and brokers for equities and futures. Keys are encrypted with a key derived from your OS keychain and stored in ~/forge-data/keys.enc; they are used only to pull history into the local Parquet cache and are never transmitted anywhere. Backtesting needs read-only permissions — never grant trade or withdrawal rights to a backtesting key.

5.2 Data packs

Packs are planned as one-time purchases from the data catalogue: a Parquet directory plus a signed SHA-256 manifest. The engine verifies the manifest on load and refuses tampered or truncated packs. All packs are survivorship-bias-free (delisted symbols included with delisting date and final price), corporate-action adjusted (with the raw series kept), and timestamp-normalized to UTC with exchange session metadata.

Monthly refreshes are free while your update contract is active, otherwise €19 per refresh.

5.3 CSV / Parquet import

timestamp,open,high,low,close,volume
2024-01-01T00:00:00Z,42283.5,42410.0,42190.2,42355.1,1834.2

Timestamps must be ISO-8601 with a timezone; the importer refuses naive timestamps because ambiguous sessions are the number-one source of accidental lookahead. Parquet files with the same columns import directly and are faster.

6 · Integrations

6.1 Exporting a validated config

Report → Export writes <strategy>.forge-live.json, signed with your licence key:

{
  "engine_hash": "1.8.1+g7f3a2c",
  "strategy": { "class": "EmaTrend", "code_sha256": "…", "params": { "fast": 20, "slow": 50, "atr_mult": 2.5 } },
  "sizing":   { "kelly_fraction": 0.25, "max_asset_pct": 0.075, "max_gross_leverage": 1.0 },
  "guards":   { "dd_halt": -0.20, "slippage_cap_bps": 20, "kill_switch": true },
  "validated": { "range": ["2019-01-01", "2026-08-31"], "wf_efficiency": 0.71, "mc_p_dd20": 0.068 }
}

The same payload is available as CSV (one row per parameter) or as a webhook POST, so any runner can consume it. A well-behaved runner should refuse a config whose engine_hash it does not recognise and whose wf_efficiency is below 0.5. Stream realised fills back into Analyze → Drift to compare live performance with the stitched out-of-sample curve.

6.2 Importing a strategy into a notebook

Most people arrive with a strategy that already exists somewhere. Strategies → Import reads a Python file and writes a notebook from it. It accepts Python and nothing else — if your strategy is written in another platform's own scripting language you convert it to Python first, with whatever converter you use. That step is not ours, we never see the original, and we cannot report on what it cost you.

  1. Point Strategies → Import at the .py file. The importer wraps it in a Strategy subclass, maps its entries, exits and closes onto engine orders, and turns every tunable constant it can identify into a param() so walk-forward can sweep it.
  2. Read the repainting audit before you run anything. It lists every place the notebook reads data that was not available at the bar it is standing on, every intrabar assumption the engine could not honour, and every constant it promoted to a parameter without being asked. Lookahead reads are rewritten to point-in-time equivalents and flagged; none is kept silently.
  3. Run it at the shipped defaults — 20 bps slippage, 5 bps commission, next-bar fills, delisted symbols in. Do not soften them for the first run; the first run is the one every later run is compared against.
What usually goes wrong. Three things, in this order. The curve drops. Most imported strategies were tuned where slippage and commission were zero, so the first honest run is worse — that is the import working, not failing. Behaviour with no engine equivalent comes back as a warning, not a substitution: an intrabar risk rule this engine cannot honour is listed and left undone rather than quietly approximated. The parameters were already fitted before they got here, on a sample this engine never saw, and the search counter in cell [7] cannot count looks it did not watch. An imported notebook starts with a debt you cannot measure — which is why the bundled Imported signal stack is the weakest book on the list rather than a flattering one.

7 · Licensing

7.1 Licence & devices

Planned: one perpetual licence covers three concurrently activated devices. Activation requires one online check; running does not. Personal and commercial use by the licence holder is included. Backcast Labs is not on sale yet — join early access.

7.2 Update contract

Planned: twelve months of updates are included. Afterwards, €99 per year keeps you on the latest release. If you stop, you keep the last version you received — your fallback version — forever. Resuming later moves you to the current release with no back-payment. Details in Pricing; version history in the release notes.

8 · Troubleshooting

Table 6. Common errors and fixes.
SymptomCauseFix
LookaheadError: index t+1 requested at tThe strategy reads a future bar, often via a shifted arrayUse ctx.data accessors; on an imported notebook, check the repainting audit for offset indices
PackIntegrityErrorManifest mismatch — incomplete download or an edited fileRe-download from the data catalogue; never edit pack files
Efficiency ratio shows “n/a”A fold has fewer than 30 out-of-sample tradesFewer folds, longer OOS windows, or accept Monte-Carlo-only validation
Live results differ from the backtestDifferent engine hash, or a slippage-model mismatchPin both to the same release; import realised fills into the cost model
“Licence: 3 of 3 devices active”An old machine is still activatedDeactivate it from the licence settings
The interface cannot reach the enginePort 8765 in use, or a firewallforge-engine serve --bind 127.0.0.1:8766 and set the port in Settings
Questions the docs do not answer? E-mail hello@backcastlabs.com.