Import a design from a repository URL
Available now
Point OHM at a public GitHub or GitLab repository and it will read what's there into a structured design record — then hand it to you for review.
This is the fastest way to get an existing project into OHM, and the main way an organisation backfills a back catalogue without redocumenting years of work.
Doing it
Designs → Generate from URL, paste the repository address, and generate.
Only the URL is needed. Everything else is decided for you.
Most repositories come back in a few seconds. Large, mature projects — hundreds of files, years of documentation — take longer. On nodes with async jobs enabled, the web UI submits background jobs and shows real progress, so generation is no longer capped by the two-minute proxy timeout. You can paste several URLs separated by commas; each becomes its own job.
On a node you run, this is already on
docker compose up starts a worker and enables jobs, so background import
works out of the box — see run your own node. It is
what JOBS_ENABLED=true plus a running ohm-worker gets you.
If you assembled a node by hand and background import is unavailable, those
two things are what's missing. On Azure Container Apps, set
enable_jobs = true when you
deploy a node.
Operators and scripts can use the HTTP job API or the CLI:
ohm okh generate-jobs submit https://github.com/org/project --no-llm
ohm okh generate-jobs wait <job_id>
Sync path still exists
POST /api/okh/generate-from-url still runs generation in the request. Prefer
POST /api/okh/generate-from-url/jobs for anything that might take more than
a minute, or when submitting multiple URLs.
Whether an LLM is involved changes what you get back
Without one, extraction fills in most fields but leaves function —
what the hardware is for — for you to write. That is usually the only
field the review screen still needs. The generated design reports whether an
LLM contributed and, if not, why, so a thin result is never a mystery.
See Configure an LLM, including how to run a local model with ollama and no cloud key at all.
Then review it — this part is not optional
What comes back is a draft, and treating it as finished is the main way to get a bad record into the world.
Extraction reads what a repository actually says. Where documentation is implicit, inconsistent, or absent, extraction is a best guess. The review step exists because that guess needs a human.
The form is ordered by what actually needs your attention:
Required — title, version, function, documentation language, licensor, and hardware licence. A design can't be downloaded until these are filled in. Any that couldn't be extracted are marked.
The version is read, never guessed. It comes from a release or tag, a
version file at the top of the repository (VERSION, package.json,
pyproject.toml, library.properties), or the revision in a KiCad project's
schematic title block, in that order. If none exists the field is left blank
for you to fill, and the quality notes list anything version-like that was seen
elsewhere, such as v02 in file names. Declaring a version in one of those
places means the next generation picks it up.
What drives matching — manufacturing processes, materials, bill of materials. These decide which workshops can build this, so they're worth more of your time than anything else on the page. Check the materials especially — they're the most error-prone part of extraction, and prose gets misread as components more often than we'd like.
The process list is the one to edit. The generator keeps a process only when
it is in the manufacturing taxonomy, under that taxonomy's name, and drops
anything else it proposed. A manifest also records each process
as a requirement entry and, for processes that have one, a TSDC code. Those
follow the list whenever a design is saved, by any client: remove a process
and its requirement and code go with it, while detail you added to a process
you kept stays. The review form does the same as you edit — the TSDC codes are
shown under the processes rather than edited on their own, and download waits
until they are up to date. To apply the same rule to a file without saving it, use
ohm okh normalize my-design.okh.yaml or POST /api/okh/normalize.
The bill of materials is read from your BOM file. A file named like a BOM —
BOM.csv, bill_of_materials.csv, board_bom.csv, or an assembly-service
export such as BOM_JLCPCB.csv — is linked as the BOM's external_file, and
its rows become the components, with quantities. KiCad and JLCPCB exports are
read as they come: parts are named by their value (10uF), and a row with no
quantity column counts its designators. If there are several, the plainest name
is the one linked.
Being found — description, repository, keywords.
Everything else — collapsed, but present. Nothing extracted is hidden from you.
Processes and keywords edit as removable tags. Nested structures like materials and the bill of materials are shown as-is with a JSON editor, rather than a half-built structured form that might quietly drop a field. The bill of materials also says what it is — the parts needed to build the design — and which file it was read from.
Then download it
When the required fields are valid, download the design as YAML or JSON.
YAML is the better choice if a person will read or edit the file afterwards — much of the OKH ecosystem uses it, and it's far easier to scan than JSON. JSON is the better choice if software is going to consume it directly.
Saving writes the design to this node
Save to this node stores the reviewed design as private, under your account. The record page has the visibility control, so sharing is a separate choice. The generation record is stored beside the design, not inside it, and the record page can open that view again. Download still keeps a copy on this computer. Someone who is not signed in sees Sign in to save instead.
What the generator did, and why
Every run also produces a provenance record — a second file beside the manifest, not part of it:
It carries the stage timeline and, for each field, which layer produced it, by what method, at what confidence, and from where:
{
"fields": {
"title": {"layer": "direct", "method": "metadata_name",
"confidence": 0.91, "source": "metadata.name"},
"description": {"layer": "nlp", "method": "readme_summary",
"confidence": 0.62, "source": "README.md"}
}
}
That is what makes review possible rather than guesswork. A field read straight from repository metadata and a field inferred from prose are not equally trustworthy, and the record tells you which you are looking at.
source is a short label — metadata.name, README.md, VERSION —
naming where the extractor looked. It is not an excerpt, and does not point at
a line.
Why it is a separate file
A manifest's content hash is taken over the whole file, and that hash is
what pins a package and dedups the federation catalogue. Recording how a
design was made inside the design itself would give the same design two
different addresses. So the manifest stays exactly what it would have been,
and the record travels beside it — in the downloaded file, and, once you
save, in its own object on the node keyed by the design's id.
ohm okh generation-provenance <id> reads that object back.
It is always produced — there is no flag to remember, because the run worth explaining is invariably the one you did not think to ask about.
When it doesn't work
"That repository couldn't be read." Private, misspelled, or moved. Only public repositories work — private ones need credentials that belong to you, which needs accounts.
"Generating with the language model needs an account on this node." The node has a language model, and spends it only for people with an account here. Register opens on this page, so the address you typed stays put, and you can generate again with the model. Or choose Generate without the language model to run the same address on rules alone, straight away.
"The shared rate limit has been reached." Everyone using the hosted instance shares one quota for reading repositories, so heavy use by one person affects others. Waiting is the fix. This goes away if you run your own node with your own credentials.
It read the repository but got little out of it. That's a documentation signal, not a failure. A repository that doesn't say what its parts are made of gives extraction nothing to find. Fill in what you know and move on.
A realistic expectation
Extraction on the hosted instance runs on rules rather than a language model. It's fast, free, predictable, and works offline — and it's less clever than you might expect. It finds what's stated plainly and misses what's implied.
That's the trade, and the guided review is how it's made to work. Assume you'll correct something on every design, and it will rarely disappoint you.