Skip to content
Source

Upload from a script or an agent

Your build makes images, or your coding agent makes a screenshot for a pull request. You want them on the forge without a browser.

The src CLI, the REST API and the MCP server can do everything that the Assets tab does. They use a token, so they act as you, or as the agent session that holds the token.

With src

You need src, logged in. Run the commands in a clone of the repository, or add -R OWNER/REPO.

src asset push dist/hero.png --to images      # uploads images/hero.png
src asset push logo.svg favicon.ico           # uploads to the top level
src asset list images/
src asset versions images/hero.png
src asset restore images/hero.png 2
  • push uploads each file under its own name, in the folder of --to. A file with the same bytes as the current version prints Unchanged and adds no version.
  • list and versions take --json. The url and pinnedUrl fields give the two URLs of each asset.
  • restore makes a version current again.

To hide, delete, or change who can see the assets:

src asset hide images/draft.png               # --unhide shows it again
src asset delete images/old.png --version 1 --yes
src asset visibility public                   # admins, private repositories only

src asset delete needs --yes, because src never asks a question. Without --version, it deletes the asset with all its versions.

Pull the assets into a folder

Your site can link to the URLs, so most builds need no copy. If your build must ship the files itself, pull them:

src asset pull --dir public
  • It writes each asset to public/<path>. Give a prefix, such as src asset pull images/ --dir public, to pull only one folder.
  • It skips a file that has the same bytes already, and writes over a file with other bytes.
  • It never writes outside --dir, and never into a git folder. It names each file that it did not write, writes the others, then exits 1.

With REST

The routes are under /api/v1/repos/{owner}/{repo}, and they take a token in the Authorization header. Percent-encode each segment of the path: a space is %20, and # is %23.

Upload a file. The body is the file. X-Content-SHA256 is its SHA-256, and curl sends the Content-Length:

export TSS_FORGE_URL=https://forge.example/api/v1
export TSS_TOKEN=<your personal access token>

FILE=dist/hero.png
SHA=$(sha256sum "$FILE" | cut -d ' ' -f 1)
curl -X PUT "$TSS_FORGE_URL/repos/acme/site/assets/files/images/hero.png" \
  -H "Authorization: Bearer $TSS_TOKEN" \
  -H "Content-Type: application/octet-stream" \
  -H "X-Content-SHA256: $SHA" \
  --data-binary "@$FILE"

The answer is 201 for a new version, and 200 when the bytes are the current version already. Its JSON has version, created, url and pinnedUrl. A body that does not match the SHA-256 gets 422.

Read:

RouteDoes
GET /assets?prefix=&cursor=Lists one page of assets as { assets, next }. Send next back as cursor for the next page.
GET /assets/versions/{path}Lists the versions of an asset, newest first, with currentVersion and hidden.

Change:

RouteDoes
PUT /assets/files/{path}Uploads a new version and makes it current.
POST /assets/current/{path} with {"version": 2}Makes a version current.
POST /assets/hidden/{path} with {"hidden": true}Hides the asset. false shows it again.
DELETE /assets/files/{path}Deletes the asset with all its versions. Add ?v=<n> to delete one version.
PUT /assets/visibility with {"public": true}Admins: makes the assets of a private repository public, or private with false.

With MCP

The MCP server at /mcp has tools for the same features as REST. The tools take the same fields as the routes, with path as a field.

  • Read: list_assets, asset_versions.
  • Upload: upload_asset. The content field is the file as base64, at most 5 MiB. Upload a larger file with src or REST.
  • Change: set_asset_current, set_asset_hidden, delete_asset_version, delete_asset.
  • Admins: set_assets_public.

Who can change assets

  • People with write access, and their tokens.
  • Agent sessions act as their person, and never with more access. A fixer session can change assets. A reviewer or investigator session can only read them.
  • CI jobs can read assets, but cannot change them.

Limits

  • A file is at most 100 MiB.
  • The assets of one repository hold at most 10 GiB. The same bytes count once. Old versions count until you delete them.
  • An upload over MCP is at most 5 MiB.

Your build uploads its files, and your pages link to their URLs. Versions and caching shows how to roll back when an upload goes wrong.