Interacting with Tesseracts¶
You’ve built a Tesseract — now let’s put it to work. This page walks through calling a Tesseract from all three interfaces (CLI, REST API, and Python SDK), computing derivatives, and reading a Tesseract’s schema so you know exactly what it expects. We recommend working through Get Started and Creating Tesseracts first.
We’ll use the vectoradd Tesseract from the examples,
which computes s·a + b for two vectors a, b and a scalar s. Build it the
same way you built helloworld:
$ tesseract build examples/vectoradd
See what’s running¶
Some ways of calling a Tesseract (the REST API, or a served Python session) need a running container. To list every Tesseract currently running on your machine:
$ tesseract ps
The output is a table showing each container’s ID, name, version, host port, project ID, and description:
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ ID ┃ Name ┃ Version ┃ Host Port ┃ Project ID ┃ Description ┃
┡━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ 997fca92ea37 │ vectoradd │ 1.2.3 │ 56434 │ tesseract-afn60xa27hih │ Simple tesseract that adds two vectors.\n │
└──────────────┴───────────┴─────────┴───────────┴────────────────────────┴───────────────────────────────────────────┘
Two columns you’ll reach for often:
Host Port — the port to use when calling the Tesseract’s REST endpoints.
Project ID — pass this to
tesseract teardownto stop all containers in that project.
Invoke the apply endpoint¶
Every Tesseract’s core operation is apply — for vectoradd it’s the vector
sum, but in general this could be a neural network forward pass, a simulation
step, or any other computation. Let’s call it with a = (1, 2, 3) and
b = (4, 5, 6), which should give us (5, 7, 9).
Pick whichever interface fits how you’re working — all three return the same result:
$ tesseract run vectoradd apply @examples/vectoradd/example_inputs.json
{"result":{"object_type":"array","shape":[3],"dtype":"float64","data":{"buffer":[5.0,7.0,9.0],"encoding":"json"}}}
The @ prefix tells the CLI to read the input payload from a file:
{
"inputs": {
"a": {
"object_type": "array",
"shape": [3],
"dtype": "int64",
"data": {
"buffer": [1, 2, 3],
"encoding": "json"
}
},
"b": {
"object_type": "array",
"shape": [3],
"dtype": "int64",
"data": {
"buffer": [4, 5, 6],
"encoding": "json"
}
}
}
}
For small payloads, you can also pass JSON inline:
$ tesseract run vectoradd apply '{"inputs": {"a": ..., "b": ...}}'
First make sure the Tesseract is running (check tesseract ps), or launch it with:
$ tesseract serve vectoradd
Then post to its /apply endpoint, using the host port from tesseract ps:
$ curl http://<tesseract-address>:<port>/apply \ # Replace with actual address
-H "Content-Type: application/json" \
-d @examples/vectoradd/example_inputs.json
{"result":{"object_type":"array","shape":[3],"dtype":"float64","data":{"buffer":[5.0,7.0,9.0],"encoding":"json"}}}
The payload posted to /apply is:
{
"inputs": {
"a": {
"object_type": "array",
"shape": [3],
"dtype": "int64",
"data": {
"buffer": [1, 2, 3],
"encoding": "json"
}
},
"b": {
"object_type": "array",
"shape": [3],
"dtype": "int64",
"data": {
"buffer": [4, 5, 6],
"encoding": "json"
}
}
}
}
>>> import numpy as np
>>> from tesseract_core import Tesseract
>>>
>>> a = np.array([1.0, 2.0, 3.0])
>>> b = np.array([4.0, 5.0, 6.0])
>>>
>>> with Tesseract.from_image(image="vectoradd") as vectoradd:
... vectoradd.apply({"a": a, "b": b})
{'result': array([5., 7., 9.])}
The Tesseract context manager starts the container locally and tears it down when the context exits, so you don’t have to manage its lifecycle by hand.
Tip
To connect to a Tesseract that’s already running elsewhere, use Tesseract.from_url(...) instead.
Notice the shape of the result. Over the CLI and REST API, arrays come back in a
structured JSON form that records the dtype, shape, and encoding alongside
the raw buffer — this is what makes Tesseract outputs self-describing across
languages. The Python SDK unpacks that form into a NumPy array for you.
Compute derivatives¶
vectoradd is differentiable: it was built with Differentiable inputs and
outputs, so it exposes derivative endpoints in addition to apply. (If you
haven’t yet met differentiable Tesseracts, the
Differentiability section of the previous page introduces
them.)
Let’s compute the Jacobian of result with respect to a at the same point,
a = (1, 2, 3), b = (4, 5, 6). Since result = s·a + b with s = 1, we
expect the 3×3 identity matrix:
$ tesseract run vectoradd jacobian @examples/vectoradd/example_jacobian_inputs.json
{"result":{"a":{"object_type":"array","shape":[3,3],"dtype":"float64","data":{"buffer":[[1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,1.0]],"encoding":"json"}}}}
$ curl -d @examples/vectoradd/example_jacobian_inputs.json \
-H "Content-Type: application/json" \
http://<tesseract-address>:<port>/jacobian
{"result":{"a":{"object_type":"array","shape":[3,3],"dtype":"float64","data":{"buffer":[[1.0,0.0,0.0],[0.0,1.0,0.0],[0.0,0.0,1.0]],"encoding":"json"}}}}
>>> import numpy as np
>>> from tesseract_core import Tesseract
>>>
>>> a = np.array([1.0, 2.0, 3.0])
>>> b = np.array([4.0, 5.0, 6.0])
>>>
>>> with Tesseract.from_image("vectoradd") as vectoradd:
... vectoradd.jacobian({"a": a, "b": b}, jac_inputs=["a"], jac_outputs=["result"])
{'result': {'a': array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])}}
A derivative endpoint takes the same inputs as apply, plus two extra fields
that say what to differentiate: jac_inputs (which inputs to differentiate
with respect to) and jac_outputs (which outputs to differentiate). For the CLI
and REST API, those live in the payload:
{
"inputs": {
"a": {
"object_type": "array",
"shape": [3],
"dtype": "int64",
"data": {
"buffer": [1, 2, 3],
"encoding": "json"
}
},
"b": {
"object_type": "array",
"shape": [3],
"dtype": "int64",
"data": {
"buffer": [4, 5, 6],
"encoding": "json"
}
}
},
"jac_inputs": ["a"],
"jac_outputs": ["result"]
}
Only fields marked Differentiable may appear in jac_inputs / jac_outputs;
asking for a non-differentiable field raises a validation error before the
endpoint runs. Alongside jacobian, Tesseracts can expose the
jacobian_vector_product (JVP) and vector_jacobian_product (VJP) endpoints —
these are what Tesseract-JAX and
Tesseract-Torch use under the
hood to make gradients flow through your Tesseract automatically. See
Differentiable Programming for what each one computes.
Not every Tesseract implements every endpoint. To check which ones a Tesseract supports:
>>> with Tesseract.from_image("vectoradd") as vectoradd:
... print(vectoradd.available_endpoints)
['apply', 'jacobian', 'health']
vectoradd implements jacobian but not JVP or VJP, so those don’t appear.
Equivalently, run tesseract apidoc vectoradd or open the /docs endpoint of a
running Tesseract in your browser.
Read a Tesseract’s schema¶
Because each Tesseract has its own input/output signature, you’ll often want to discover that signature programmatically — for validation, for building a UI, or just to remind yourself what a Tesseract expects. Every Tesseract can emit its schema in OpenAPI format:
$ tesseract run vectoradd openapi-schema
$ curl <tesseract-address>:<port>/openapi.json
>>> from tesseract_core import Tesseract
>>> with Tesseract.from_image("vectoradd") as vectoradd:
... schema = vectoradd.openapi_schema
The OpenAPI schema covers every endpoint, though they’re all derived from the
apply input/output schemas. It’s built for machines; for a human-readable
view, run tesseract apidoc vectoradd or open a running Tesseract’s /docs
endpoint.
What’s next¶
You can now build a Tesseract and drive it through all three interfaces, including its derivatives. From here:
Composing Tesseracts into Pipelines — chain several Tesseracts into a larger differentiable workflow.
Differentiable Programming Basics — how the
jacobian, JVP, and VJP endpoints relate, and how to implement them.Demos & Tutorials — full end-to-end demos: data assimilation, shape optimization, and more.