Skip to main content
You can use the LangSmith Python and TypeScript SDKs to manage agent repos and skill repos in the Context Hub programmatically: pull a context for use at runtime, push a new commit, list and search repos, check existence, and delete repos.

Install packages

pip install -U langsmith

Configure environment variables

If you already have LANGSMITH_API_KEY set for your workspace, you can skip this step. Otherwise, create one in Settings > API Keys > Create API Key in LangSmith.
export LANGSMITH_API_KEY="lsv2_..."

Identifiers

Most methods accept an identifier string that names a context repo. The accepted forms are:
  • name — resolves against the current workspace owner.
  • owner/name — fully qualified.
  • owner/name:version — pinned to a specific commit hash or tag.
The optional version argument on pull methods overrides any version embedded in the identifier. If no version is provided, the latest commit is returned.

Schemas

Contexts are made up of typed entries. An entry is either a file with inline content or a link to another agent or skill repo.
from langsmith.schemas import (
    AgentContext,
    AgentEntry,
    Entry,
    FileEntry,
    SkillContext,
    SkillEntry,
)

# A file with inline content.
file = FileEntry(content="You are a helpful assistant.")

# A link to another agent repo (optionally pinned to a commit).
agent_link = AgentEntry(repo_handle="email-assistant")

# A link to a skill repo (optionally pinned to a commit).
skill_link = SkillEntry(repo_handle="deep-research")
AgentContext and SkillContext are the response shapes returned when you pull a repo. Both contain:
FieldTypeDescription
ownerstringThe handle of the repo owner.
repostringThe repo name.
commit_idUUID / stringThe unique ID of the commit.
commit_hashstringThe content-addressable commit hash.
filesdict[str, Entry]The files in the commit, keyed by their path.

Push an agent

Create a new agent repo or commit a new version of an existing one. If the repo doesn’t exist yet, it is created with the metadata you provide (description, readme, tags, is_public); if it already exists, those fields are patched only when explicitly passed. The method returns a URL pointing to the new commit in the LangSmith UI.
from langsmith import Client
from langsmith.schemas import FileEntry

client = Client()

url = client.context.push_agent(
    "email-assistant",
    files={
        "AGENTS.md": FileEntry(
            content="You are an email triage assistant.",
        ),
        "tools.json": FileEntry(content='{"tools": []}'),
    },
    description="Triages and drafts replies to incoming email.",
    tags=["email", "productivity"],
    is_public=False,
)
print(url)

Parameters

ParameterTypeDescription
identifierstringThe agent’s identifier.
filesdict[str, Entry | None]Map of file path to Entry. Pass None / null to delete a path in this commit.
parent_commit / parentCommitstring (optional)Parent commit hash for optimistic concurrency. Must be 8–64 hex characters when provided.
descriptionstring (optional)Repo description; set on creation or patched on update.
readmestring (optional)Repo readme content.
tagsstring[] (optional)Repo tags.
is_public / isPublicboolean (optional)Whether the repo is publicly discoverable.

Push a skill

Identical surface to push_agent, but commits to a skill repo. Use this for reusable capabilities that other agents can depend on.
from langsmith import Client
from langsmith.schemas import FileEntry

client = Client()

url = client.context.push_skill(
    "deep-research",
    files={
        "SKILL.md": FileEntry(content="Conduct deep multi-step research."),
    },
    description="Multi-step web research with citations.",
    tags=["research"],
)
print(url)

Pull an agent

Pull a snapshot of an agent repo. By default the latest commit is returned; pass a commit hash or tag via version (or embed it in the identifier as owner/name:version) to pull a specific version.
from langsmith import Client

client = Client()

agent = client.context.pull_agent("email-assistant")
print(agent.commit_hash)
print(list(agent.files))

# Pull a specific commit.
pinned = client.context.pull_agent("email-assistant", version="7ca95573")

# Pull a tagged commit (for example, the production tag).
prod = client.context.pull_agent("email-assistant:production")

Parameters

ParameterTypeDescription
identifierstringThe agent’s identifier. May include an inline version: owner/name:version.
versionstring (optional)Commit hash or tag to pull. Overrides any version embedded in the identifier.
Returns an AgentContext.

Pull a skill

Same shape as pull_agent, returning a SkillContext.
from langsmith import Client

client = Client()

skill = client.context.pull_skill("deep-research")
print(skill.files["SKILL.md"].content)

Check whether a repo exists

Use these methods to check whether an agent or skill repo exists in your workspace before pushing or pulling.
from langsmith import Client

client = Client()

if client.context.agent_exists("email-assistant"):
    print("agent already exists")

if not client.context.skill_exists("deep-research"):
    print("skill not found")

List agents and skills

List repos of either type, with optional filters for visibility, archived state, and a search query.
from langsmith import Client

client = Client()

# Python returns a paginated response.
result = client.context.list_agents(limit=20, query="email")
for repo in result.repos:
    print(repo.repo_handle)

skills = client.context.list_skills(is_public=True)

Parameters

ParameterTypeDescription
limitint (Python only)Maximum number of repos to return per page. Defaults to 100.
offsetint (Python only)Number of repos to skip. Defaults to 0.
is_public / isPublicboolean (optional)Filter to only public (or only private) repos.
is_archived / isArchivedboolean (optional)Filter by archived state. Defaults to False.
querystring (optional)Search query matched as a prefix against the repo handle.
Python’s list_agents / list_skills return a ListPromptsResponse with explicit limit and offset for manual pagination. TypeScript’s listAgents / listSkills return an AsyncIterableIterator that handles pagination automatically as you consume it.

Delete an agent or skill

Delete a repo and all its owned child file repos. This operation cannot be undone.
from langsmith import Client

client = Client()

client.context.delete_agent("email-assistant")
client.context.delete_skill("deep-research")

Async usage (Python)

Every method on client.context has an async equivalent on AsyncClient.context. The signatures and return types are identical; only the call site differs.
Python
from langsmith import AsyncClient

client = AsyncClient()

agent = await client.context.pull_agent("email-assistant")
url = await client.context.push_agent(
    "email-assistant",
    files={"AGENTS.md": FileEntry(content="...")},
)
The TypeScript SDK is async by default; there is no separate async client.

Errors

ErrorWhen it’s raised
LangSmithUserErrorInvalid repo_handle, malformed parent_commit, or other client-side validation.
LangSmithNotFoundErrorPulling a repo or commit that does not exist.
LangSmithConflictErrorConcurrent commit collision when parent_commit does not match the latest commit.
HTTPErrorAny other server-side failure during the request.
TypeScript surfaces these as standard Error instances. Use the provided isLangSmithNotFoundError / isLangSmithConflictError helpers to discriminate.