TogoPackage is a container image that bundles RDF and bioinformatics services into one runtime.
The primary way to use it is to pull ghcr.io/dbcls/togopackage:latest, bind-mount a data directory, and access the services through http://localhost:10005.
Building a local image from this repository is intended for development work on TogoPackage itself.
Available services:
sparql-proxy: SPARQL endpoint and admin interfaceQLever: SPARQL backendVirtuoso: additional SPARQL backendsparqlist: SPARQL-based API buildergrasp: GraphQL service for RDF resourcestabulae: query-driven tabular data publishertogomcp: MCP server for RDF Portal databases- dashboard: runtime status and log viewer
- Quick Start
- Prepare config.yaml
- Open the Services
- Data Directories
- Update Input Data
- Generated Artifacts
- Use Docker or Podman
- Developer Workflow
- Stop and Restart
- Common Pitfalls
- Repository Layout
- Component READMEs
Prerequisite: Docker or Podman.
- Pull
ghcr.io/dbcls/togopackage:latest. - Prepare
config.yamland source files in your bind-mounted data directory, or use./data.examplefor the bundled demo. - Start the container.
- Open
http://localhost:10005/. - If startup is still in progress, inspect logs with your container runtime.
The container should run as the calling user because the runtime writes generated files, caches, and database state back into the bind-mounted data directory.
Minimal example with Docker:
docker pull ghcr.io/dbcls/togopackage:latest
docker run -d --name togopackage \
-u "$(id -u):$(id -g)" \
-p 10005:10005 -p 7001:7001 -p 8890:8890 \
-v "$(pwd)/data.example:/data" \
ghcr.io/dbcls/togopackage:latestMinimal example with Podman:
podman pull ghcr.io/dbcls/togopackage:latest
podman run -d --name togopackage \
--userns keep-id -u "$(id -u):$(id -g)" \
-p 10005:10005 -p 7001:7001 -p 8890:8890 \
-v "$(pwd)/data.example:/data" \
ghcr.io/dbcls/togopackage:latestThis uses the tracked files under ./data.example/ as a demo input, including a small RDF-config example under ./data.example/rdf-config/.
To use a different bind-mounted directory with Docker:
docker run -d --name togopackage \
-u "$(id -u):$(id -g)" \
-p 10005:10005 -p 7001:7001 -p 8890:8890 \
-v "/path/to/data:/data" \
ghcr.io/dbcls/togopackage:latestTo use a different bind-mounted directory with Podman:
podman run -d --name togopackage \
--userns keep-id -u "$(id -u):$(id -g)" \
-p 10005:10005 -p 7001:7001 -p 8890:8890 \
-v "/path/to/data:/data" \
ghcr.io/dbcls/togopackage:latestThe bundled demo configuration is:
source:
- name: Demo dataset
path: ./sources/demo.ttl
format: ttl
graph: http://example.org/graph/demoThe container publishes:
10005: public entrypoint through Caddy7001: direct QLever port8890: direct Virtuoso HTTP port
/data/config.yaml is the main runtime input definition.
Each source entry must specify path.
You can choose which SPARQL backend TogoPackage uses with sparql_backend.
You can choose which MCP server TogoPackage exposes on /mcp with mcp_server.
In the examples above, the host-side bind-mounted directory is ./data.example or /path/to/data.
TogoPackage reads config.yaml from that mounted directory.
The repository includes demo input files under ./data.example/, including a small RDF-config example under ./data.example/rdf-config/.
You can either use ./data.example directly or use it as a reference when preparing your own bind-mounted directory.
sparql_backend: qlever
mcp_server: togomcp
sparql_proxy:
ADMIN_PASSWORD: your-sparql-proxy-admin-password
sparqlist:
ADMIN_PASSWORD: your-sparqlist-admin-password
qlever:
server:
ACCESS_TOKEN: your-access-token
MEMORY_FOR_QUERIES: 2G
TIMEOUT: 30s
CACHE_MAX_SIZE: 2G
CACHE_MAX_SIZE_SINGLE_ENTRY: 1G
CACHE_MAX_NUM_ENTRIES: "200"
virtuoso:
server:
DBA_PASSWORD: dba
NUMBER_OF_BUFFERS: 1500000
MAX_DIRTY_BUFFERS: 1125000
MAX_CHECKPOINT_REMAP: 1000
CHECKPOINT_INTERVAL: 60
MAX_QUERY_MEM: 2G
SERVER_THREADS: 10
MAX_CLIENT_CONNECTIONS: 10
source:
- name: Local RDF file
path: ./sources/local.ttl.gz
format: ttl
graph: http://example.org/graph/local
- name: Local RDF files by glob
path: ./sources/**/*.ttl.gz
format: ttl
graph: http://example.org/graph/batch
- name: BZip2-compressed RDF source
path: ./sources/local.ttl.bz2
format: ttl
- name: XZ-compressed RDF source
path: ./sources/local.ttl.xz
format: ttl
- name: N-Triples source
path: ./sources/local.nt
format: nt
- name: N-Quads source
path: ./sources/local.nq.zst
format: nqRules:
sparql_backendis optional. Supported values:qlever,virtuososparql_backendselects the backend used by TogoPackage for SPARQL serving and data preparationsparql-proxyforwards/sparqlto the backend selected bysparql_backend- Default
sparql_backend:qlever mcp_serveris optional. Supported values:togomcp,rdf-config-mcpmcp_serverselects the MCP service exposed at/mcp/sseand/messagesare only provided bytogomcp- Default
mcp_server:togomcp sparql_proxyis optionalsparql_proxy.ADMIN_PASSWORDis optional. Default:passwordqleveris optionalqlever.serveris optionalqlever.server.ACCESS_TOKENis optional. If omitted, QLever uses its own default behaviorqlever.server.MEMORY_FOR_QUERIESis optional. Default:2Gqlever.server.TIMEOUTis optional. If omitted, TogoPackage does not pass--timeoutqlever.server.CACHE_MAX_SIZEis optional. If omitted, TogoPackage does not pass--cache-max-sizeqlever.server.CACHE_MAX_SIZE_SINGLE_ENTRYis optional. If omitted, TogoPackage does not pass--cache-max-size-single-entryqlever.server.CACHE_MAX_NUM_ENTRIESis optional. If omitted, TogoPackage does not pass--cache-max-num-entriesqlever.server.PERSIST_UPDATESis optional. Default:false. Onlytrueadds--persist-updatessparqlistis optionalsparqlist.ADMIN_PASSWORDis optional. If omitted, SPARQList admin features are disabledvirtuosois optionalvirtuoso.serveris optionalvirtuoso.server.DBA_PASSWORDis optional. Default:dbavirtuoso.server.NUMBER_OF_BUFFERSis optional. Default:1500000virtuoso.server.MAX_DIRTY_BUFFERSis optional. Default:1125000virtuoso.server.MAX_CHECKPOINT_REMAPis optional. Default:1000virtuoso.server.CHECKPOINT_INTERVALis optional. Default:60virtuoso.server.MAX_QUERY_MEMis optional. Default:2Gvirtuoso.server.SERVER_THREADSis optional. Default:10virtuoso.server.MAX_CLIENT_CONNECTIONSis optional. Default:10- TogoPackage revokes
SPARQL_UPDATEfrom Virtuoso's publicSPARQLaccount during setup so the public endpoint stays read-only - Virtuoso numeric tuning values are YAML integers. Use strings only for values with units such as
MAX_QUERY_MEM - Virtuoso ports and data paths cannot be changed from
config.yamlbecause they are tied to other runtime services and exposed port assumptions formatcan be specified for eachsourcesource.formatis optional. Default:ttl- Supported formats:
nt,ttl,nq - Supported compressed source suffixes:
.gz,.bz2,.xz,.zst,.zstd - When a source
formatisnq, that source must not specifygraph - Relative
pathvalues are resolved from the directory containingconfig.yaml - Glob matches are expanded in sorted order
- Directories matched by a glob are ignored
graphis optional. If omitted, data is loaded into the default graph- Virtuoso does not pin a special
DefaultGraph; its default SPARQL dataset uses all loaded graphs config.yamlis parsed strictly by the supervisor. Unknown keys or invalid YAML cause startup to fail
Open these URLs after the container starts:
/-> supervisor dashboard/logs-> supervisor log viewer/sparql->sparql-proxy/sparqlist->sparqlist/grasp->grasp/tabulae-> static files fromtabulae/mcp-> MCP server selected bymcp_server/sse->togomcponly/messages->togomcponly
Direct container ports:
7001->QLever8890->Virtuoso
Main mounted runtime directory on the host: /path/to/data in generic examples, or ./data.example in the bundled demo
/path/to/data/config.yaml: main source definition/path/to/data/qlever: QLever index data/path/to/data/virtuoso: Virtuoso configuration, DB files, and load metadata/path/to/data/sources: prepared source files/path/to/data/sparqlist: generated SPARQList repository/path/to/data/grasp: generated Grasp resources/path/to/data/tabulae/queries: Tabulae query files/path/to/data/tabulae/dist: generated Tabulae output/path/to/data/togomcp/mie: user-provided MIE files/path/to/data/rdf-config: RDF-config models used by generators
If /path/to/data/rdf-config contains model directories with model.yaml, TogoPackage generates derived assets for supported services at startup.
If /path/to/data/grasp already contains .graphql files, TogoPackage keeps them and skips Grasp generation from RDF-config.
Normal workflow:
- Update
config.yamlor files under the bind-mounted data directory. - Restart the container.
- Check container logs if indexing or generation takes time.
Important behavior:
- Source files are copied under the mounted data directory, typically
/path/to/data/sources - Restarting the container reuses prepared local copies until the source files change
This section summarizes what TogoPackage prepares at startup.
- The source manifest at
/path/to/data/sources/source-manifest.jsonis prepared regardless of the selected backend - QLever or Virtuoso preparation runs according to
sparql_backend QLever- Builds or reuses indexes under
/path/to/data/qlever/index - Tracks the current input hash in
/path/to/data/qlever/index/.loaded-input-hash - Rebuilds when
/data/config.yamlor resolved source files change
- Builds or reuses indexes under
- Input refresh
- Updating a
.gzsource also refreshes the decompressed file used by loaders
- Updating a
Virtuoso- Generates
/tmp/togopackage-virtuoso/virtuoso.inion first startup - Stores DB files under
/path/to/data/virtuoso/db - Reuses
/path/to/data/sources/source-manifest.jsondirectly - Writes
/path/to/data/virtuoso/load.sql - Inserts
checkpoint;after each source file load inload.sql - Reloads when
/data/config.yamlor resolved source files change
- Generates
sparqlist- Generates repository files under
/path/to/data/sparqlistfrom/path/to/data/rdf-config - Falls back to
/togo/defaults/sparqlistwhen generation produces no files
- Generates repository files under
grasp- Keeps existing
.graphqlfiles under/path/to/data/graspif present - Otherwise generates resources under
/path/to/data/graspfrom/path/to/data/rdf-config - Uses
/togo/defaults/grasponly when/path/to/data/grasphas no.graphqlfiles and/path/to/data/rdf-confighas no model directories
- Keeps existing
tabulae- Generates query files under
/path/to/data/tabulae/queries/layer1when queries are absent - Builds output under
/path/to/data/tabulae/dist - Generated query files include pagination metadata comments such as
# Paginate: 10000
- Generates query files under
togomcp- Rebuilds runtime MIE files only from
/path/to/data/togomcp/mie - Rebuilds runtime endpoints automatically from runtime MIE files
- Generated TogoMCP endpoints always target the local
sparql-proxyendpoint - If no user-provided TogoMCP MIE files exist, TogoMCP starts with no runtime MIE files and an empty endpoints list
- Removing a user-provided MIE file is reflected on the next container restart
- Rebuilds runtime MIE files only from
To force regeneration for generated content, remove the corresponding directory under /path/to/data and restart the container.
For Grasp generated from RDF-config, remove /path/to/data/grasp/*.graphql first. If .graphql files remain there, they are treated as user-managed resources and are kept as-is.
Docker example:
docker pull ghcr.io/dbcls/togopackage:latest
docker run -d --name togopackage \
-u "$(id -u):$(id -g)" \
-p 10005:10005 -p 7001:7001 -p 8890:8890 \
-v "$(pwd)/data:/data" \
ghcr.io/dbcls/togopackage:latestPodman example:
podman pull ghcr.io/dbcls/togopackage:latest
podman run -d --name togopackage \
--userns keep-id -u "$(id -u):$(id -g)" \
-p 10005:10005 -p 7001:7001 -p 8890:8890 \
-v "$(pwd)/data:/data" \
ghcr.io/dbcls/togopackage:latestBoth runtimes should start the container as the calling user so the bind-mounted data directory stays writable.
With rootless Podman, --userns keep-id preserves that mapping on the bind mount.
Pulling ghcr.io/dbcls/togopackage:latest is the primary user workflow.
Building a local image from this repository is for development when you are changing TogoPackage itself.
The Makefile uses podman by default when available, otherwise docker.
You can still override the runtime through CONTAINER_RUNTIME.
The local image tag defaults to dbcls/togopackage.
make build CONTAINER_RUNTIME=podman
make start CONTAINER_RUNTIME=podman
make stop CONTAINER_RUNTIME=podmanYou can override the local image tag if needed:
make build IMAGE=ghcr.io/YOUR_ORG/togopackage CONTAINER_RUNTIME=dockerDocker:
docker stop togopackage
docker rm togopackage
docker run -d --name togopackage \
-u "$(id -u):$(id -g)" \
-p 10005:10005 -p 7001:7001 -p 8890:8890 \
-v "$(pwd)/data:/data" \
ghcr.io/dbcls/togopackage:latestWith Podman:
podman stop togopackage
podman rm togopackage
podman run -d --name togopackage \
--userns keep-id -u "$(id -u):$(id -g)" \
-p 10005:10005 -p 7001:7001 -p 8890:8890 \
-v "$(pwd)/data:/data" \
ghcr.io/dbcls/togopackage:latest/data/config.yamlis required inside the container, so the host bind mount must provideconfig.yamlat its rootsourcemust not be empty- Cached files under the mounted data directory are reused unless you remove them
sparqlist,grasp, andtabulaegenerate richer output when/data/rdf-configis providedtabulaerequires query files under/data/tabulae/queriesor enough RDF-config input to generate them- Keep using the same host directory for
/dataacross restarts make buildandmake startare developer-oriented local image workflows, not the primary user workflow
Most users only need a bind-mounted data directory and the published container image. If you work on this repository itself, these directories are the main entry points:
packaging/: container build files, bundled defaults, and runtime setup scriptssupervisor/: Rust-based process supervisor and dashboard servervendor/: bundled component repositories such assparql-proxy,sparqlist,grasp,rdf-config,rdf-config-mcp, andtogomcpdata/: bind-mounted runtime state, generated artifacts, caches, and local inputs
- vendor/sparql-proxy/README.md
- vendor/sparqlist/README.md
- vendor/grasp/README.md
- vendor/rdf-config/README.md
- vendor/rdf-config-mcp/README.md
- vendor/togomcp/README.md
QLever and Virtuoso do not currently have separate component READMEs in this repository.