jijzeptai
jijzeptai is the Python SDK for submitting optimization jobs and working with
Project files in JijZept AI. It supports CPython 3.11, 3.12, 3.13, and 3.14.
Install
With uv:
uv add jijzeptai
With pip:
python -m pip install jijzeptai
JijModeling and OMMX are included as required dependencies.
AI coding plugin
The SDK includes a version-matched
Agent Plugin containing one Agent
Skill with task-specific references for setup, connection checks, Solver jobs,
deployed models, Project files, and CLI management. The SDK can copy the Skill
directly into a Python project that depends on jijzeptai:
jijzeptai skill install --agent codex
Run these commands in the environment where the SDK is installed. In a
uv-managed project, prefix them with uv run. For Claude Code, use
--agent claude-code. The commands place jijzeptai in
the current project's .agents/skills/ or .claude/skills/ directory. Pass
--project PATH when running from outside the project root.
The same package includes local marketplace catalogs for Codex, Claude Code, and compatible clients. These commands print absolute paths inside the installed SDK:
jijzeptai plugin path
jijzeptai marketplace path
For example, Codex and Claude Code can register the bundled marketplace and install the same versioned plugin without GitHub CLI:
codex plugin marketplace add "$(jijzeptai marketplace path)"
codex plugin add jijzeptai@jijzeptai
claude plugin marketplace add "$(jijzeptai marketplace path)"
claude plugin install jijzeptai@jijzeptai
GitHub Copilot CLI can install the plugin directory directly:
copilot plugin install "$(jijzeptai plugin path)"
To install the bundled Skill with another skill manager, print its source
directory. The command writes one absolute path containing jijzeptai/:
jijzeptai skill path
gh skill install "$(jijzeptai skill path)" jijzeptai --from-local --agent codex --scope project
In a uv project, prefix these commands with uv run. Without the console
script, replace jijzeptai with python -m jijzeptai in any command. Choose
one manager for each destination: the SDK CLI updates only the copies that it
installed itself, while a plugin client manages plugins installed through its
marketplace.
After upgrading the project's SDK, copy the skill from that installed version:
jijzeptai skill status --agent codex
jijzeptai skill update --agent codex
status exits successfully only when the installed skill matches the current
SDK. update does not upgrade the Python package or contact a remote service.
Use jijzeptai skill remove --agent codex to remove a CLI-managed skill.
These commands refuse to overwrite another manager's installation or a
locally edited skill. Update and remove preserve the previous copy under a
hidden .jijzeptai-backup-* directory outside the agent's skills/ directory
so a late editor save cannot destroy it. Remove those backups manually after
closing editors that may still have the old files open.
Create and configure an API token
In JijZept AI, open the account menu and choose API Tokens. Create a token for the current Organization. The value appears only once, so copy it into your environment with the production JijZept AI URL and do not put it in source code:
export JIJZEPTAI_BASE_URL="https://ai.jijzept.com"
export JIJZEPTAI_API_TOKEN="<token from JijZept AI>"
DeveloperClient reads these variables by default. You can also pass
base_url="https://ai.jijzept.com" and api_token as constructor arguments
when that fits your program better.
Use an authenticated call such as list_projects() to verify that the service
accepts the token. The token's string format alone does not prove acceptance.
Project files
The client exposes Project listing, single-file transfers, selected-file transfers, and directory-tree transfers. The Organization always comes from the verified API token; these methods do not accept an Organization ID.
import os
from jijzeptai import DeveloperClient
client = DeveloperClient()
projects = client.list_projects()
project_id = projects[0].id
page = client.list_project_files(project_id, path="/data", limit=100)
while page.has_more:
page = client.list_project_files(
project_id,
path="/data",
cursor=page.next_cursor,
limit=100,
)
client.create_directory(project_id, "/data", exist_ok=True)
uploaded = client.upload_file(
project_id,
local_path="input.csv",
remote_path="/data/input.csv",
overwrite=True,
)
saved_path = client.download_file(
project_id,
remote_path=uploaded.path,
local_path="input-copy.csv",
overwrite=True,
)
client.create_directory(project_id, "/workspace/src", parents=True, exist_ok=True)
selected = client.upload_files(
project_id,
["pyproject.toml", "src/main.py"],
remote_directory="/workspace",
)
tree = client.upload_directory(
project_id,
".",
"/workspace-tree",
ignore_patterns=[".venv/", "dist/"],
)
os.makedirs("downloads", exist_ok=True)
downloaded = client.download_files(
project_id,
["pyproject.toml", "src/main.py"],
remote_directory="/workspace",
local_directory="downloads",
)
downloaded_tree = client.download_directory(
project_id,
"/workspace-tree",
"downloads/workspace-tree",
)
list_project_files accepts an absolute POSIX-style directory path. Its
cursor is opaque and belongs to the same path and pagination flow. Single-file
and multi-file methods use the same collection-shaped Developer APIs. One
upload call publishes one atomic FileTree commit within the documented
500-entry limit; an oversized selection fails before byte transfer and is not
split into partial commits. Upload refuses an existing remote path unless
overwrite=True. Download refuses an existing local path unless
overwrite=True and publishes the completed download atomically from a
temporary file. Directory methods preserve relative paths and explicit empty
directories, always exclude .git/, and reject symlinks and special entries.
Uploads and downloads use short-lived signed object-storage URLs internally.
The SDK never sends the JijZept AI Authorization header to those URLs.
Uploads bind a CRC32C checksum to the signed PUT, and downloads verify the
provider-measured CRC32C response header before atomically publishing the local
file.
If every retry loses the mutation outcome or ends in a retryable server error,
ProjectFileMutationIndeterminateError exposes the mutation Idempotency-Key.
The FileTree change may have committed; this error must not be treated as a
rollback.
Model listing in 0.5
list_models() and list_model_versions(name) now return a ModelPage, with
items and next_cursor, instead of a tuple containing every version. Calling
without arguments still works, but returns only the first page. Solver owns
the default of 20 items; an explicit limit must be between 1 and 100.
page = client.list_models()
while True:
for model in page.items:
print(model.name, model.tag)
if page.next_cursor is None:
break
page = client.list_models(cursor=page.next_cursor)
For versions of one model, use client.list_model_versions("knapsack") and
preserve that name on subsequent calls. Cursors follow immutable model ID order;
traversal covers a fixed catalog without duplicates or omissions. Concurrent
registrations do not form a snapshot, so start a new traversal to refresh it.
No method automatically collects all pages or reads individual model details.
List items contain basic version metadata without summary. Read descriptive
metadata and input_schema explicitly through the detail method:
model = client.get_model("knapsack", "demo")
input_schema = model.summary.get("input_schema") if model.summary else None
Upgrade to SDK 0.5 after the server supports the page contract. Existing SDK 0.4
callers must migrate their iteration to page.items and handle next_cursor.
Minimal model workflow
This flow deploys a reusable JijModeling model, submits input data, waits for
optimization, and downloads the solution. If the service denies deployment,
ask someone with current deployment permission to share a model's name and tag,
then call submit_job_by_deployed_model with those values if authorized (skip
deploy_model).
import jijmodeling as jm
from jijzeptai import DeveloperClient
# Define a reusable knapsack model.
@jm.Problem.define("knapsack", sense=jm.ProblemSense.MAXIMIZE)
def knapsack(problem: jm.DecoratedProblem):
values = problem.Float(ndim=1)
item_count = values.len_at(0)
weights = problem.Float(shape=(item_count,))
capacity = problem.Float()
selected = problem.BinaryVar(
"selected",
shape=(item_count,),
description="item selected",
)
problem += jm.sum(values * selected)
problem += problem.Constraint(
"capacity",
jm.sum(weights * selected) <= capacity,
)
# Create the SDK client for JijZept AI.
client = DeveloperClient()
# Publish the model so the Organization can run it with new input later.
model = client.deploy_model("knapsack", "demo", knapsack)
# Start an optimization job with concrete input values.
job = client.submit_job_by_deployed_model(
model.name,
model.tag,
{
"values": [10.0, 20.0, 15.0, 30.0],
"weights": [2.0, 3.0, 5.0, 7.0],
"capacity": 10.0,
},
)
# Wait for completed calculation, which may return no Solution.
finished = client.wait_for_success(job.job_id)
if finished.solver_result is not None and finished.solver_result.solution is None:
print(finished.solver_result.termination_reason)
else:
solution = client.download_solution(finished.job_id)
print(solution.extract_decision_variables("selected")) # selected items
print(solution.objective) # candidate objective value
print(solution.feasible) # True when all constraints hold
A succeeded job means that the calculation completed, including a search that
returned no Solution. solver_result records the reported search termination
and optional candidate facts. A Solver time limit is separate from a platform
timed_out job. not_provided means the Solver API did not provide its reason;
solver_result=None means these facts were not recorded (including historical
jobs). A candidate with feasible=False does not prove the problem infeasible.
download_solution raises NoSolutionError when a completed result has no
Solution. SDK 0.5.0 ignores solver_result and receives a ConflictError with
code solver_no_solution from that download request.
Permissions
JijZept AI checks current Organization permissions for each operation. Handle
AuthorizationError when the service denies a call and confirm current access
in JijZept AI. The SDK does not grant or change roles. Deployed models belong
to the Organization; the service determines access to jobs and results.
Errors
Catch JijZeptAIError for failures raised by this package, or
JijZeptApiError for an HTTP status, service error code, and response details.
Invalid arguments and local path or overwrite-policy violations raise
TypeError or ValueError. Authentication failures use HTTP 401, permission
failures use HTTP 403, stale FileTree writes use HTTP 409 or 412, and
unverifiable current identity or authorization state uses HTTP 503.
from jijzeptai import (
JijZeptAIError,
JijZeptApiError,
ProjectFileMutationIndeterminateError,
TransportError,
)
try:
uploaded = client.upload_file(
project_id,
local_path="input.csv",
remote_path="/data/input.csv",
)
except ProjectFileMutationIndeterminateError as error:
print(f"Upload outcome unknown; idempotency key: {error.idempotency_key}")
except TransportError as error:
print(f"Network request failed: {error}")
except JijZeptApiError as error:
print(f"API request failed ({error.status_code}): {error.message}")
except JijZeptAIError as error:
print(f"JijZept AI operation failed: {error}")
License
Apache-2.0 covers the published jijzeptai package. It does not license the
JijZept AI hosted service, API tokens, user models or data, service terms, or
JIJ Inc. trademarks and the JijZept AI product name.
Metadata
Release files for jijzeptai 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| jijzeptai-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Release files / jijzeptai-0.7.0-py3-none-any.whl
| Download URL | jijzeptai-0.7.0-py3-none-any.whl |
|---|---|
| Size | 66.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4e5da231ca15f0162882ef8f8812828d2ecd82d0293362a12ab33f6fa4b2d0fe
|
|
BLAKE2b-256 checksum How to use checksums |
744c26d01bffca1007c635043eb0936be0c23b48f561a54fed6c525ae4e010c1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 19, 2026.
Transparency log