> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs-beta.getzep.com/v3/agent-skills/learning-and-admission/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-beta.getzep.com/_mcp/server. # Configure learning and admission > Configure compilation mode, automatic or member approval, admission gates, and candidate evaluations for Agent Skills. Zep compiles closed Trajectories into Skill candidates. A candidate is not available to search until Zep admits it. Each Agent has `memory_settings` that control compilation and admission. You can set `memory_settings` when you create the Agent, and you can update the settings later. ## Compilation | `compilation_mode` | Behavior | | ------------------ | --------------------------------------------------------------------------------------------- | | `scheduled` | The default. Zep compiles a task family when it has at least three eligible attempt families. | | `on_close` | Zep compiles after each eligible attempt family closes. | | `manual` | Zep does not add new closed Trajectories to compilation automatically. | Compilation uses only Trajectories with `learn_from` set to `true`, and only successful attempt families with strong verification. For each candidate, the compiler cites the Trajectory events that support each part of the Skill. Zep scans and evaluates each candidate before admission. ## Approval The default approval is `auto`. Zep admits each new Skill version without human review, so the agent can use what it learns on the next run. Human review is an option that you enable. | `approval` | Behavior | | ---------- | ------------------------------------------------------------------------------------------------------------------------------ | | `auto` | The default. Zep admits a candidate that passes all admission gates. A candidate that does not pass a gate waits for a member. | | `manual` | Each candidate waits for a member to approve or reject it. | With `auto` approval, you can limit automatic admission to some task families. Add those task families to `auto_approval_task_families`. A candidate of a different task family then waits for a member. When the list is empty, automatic admission applies to all task families. To add human review only for high-risk Skills, keep `auto` approval and set `approval_required_tools` in the [admission gates](#admission-gates). Only a member can review a compiled candidate, with `auto` approval and with `manual` approval. The candidate review request needs a member bearer token. A project API key cannot review a compiled candidate. To review a candidate in the Zep Dashboard: 1. Open the Agent. 2. Select **Skills**. 3. Open the candidate. 4. Select **Approve candidates** or **Reject candidates**. ## Admission gates These settings add conditions to automatic admission. A candidate that does not satisfy a condition waits for a member. | Setting | Description | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `approval_minimum_attempt_families` | The minimum count of supporting attempt families for a new Skill. The value is from 1 to 16. | | `approval_required_tools` | The tool names that need a member approval. A candidate that uses one of these tools waits for a member. The default is an empty list. | | `provisional_skill_limit` | The maximum count of provisional Skills in one task family. Over the limit, a new provisional Skill waits for a member. When it is not set, no limit applies. | | `provisional_expiry_days` | The period after which Zep retires a provisional Skill that no application used. When it is not set, provisional Skills do not expire. | | `admission_evaluation_requirements` | The evaluations, for example an offline test set, that each candidate of a task family must pass before admission. Record each result with `client.agent.skill.evaluation.create_for_candidate`. | > **Note** > > Start with `approval_required_tools` for tools that change data, send messages, or move money. A member then reviews each Skill that uses those tools before an agent can retrieve it. ## Update the settings An Agent update needs the current `revision` of the Agent as `expected_revision`. When another write changed the Agent first, the API returns a conflict. Read the Agent again and send the update with the new revision. **`Python`** ```python Python from zep_cloud import AgentMemorySettings agent = client.agent.get(agent_uuid=agent_uuid) client.agent.update( agent_uuid=agent_uuid, expected_revision=agent.revision, memory_settings=AgentMemorySettings( approval="auto", compilation_mode="scheduled", approval_minimum_attempt_families=2, approval_required_tools=["billing.issue_refund"], ), ) ``` **`TypeScript`** ```typescript TypeScript const agent = await client.agent.get(agentUuid); await client.agent.update(agentUuid, { expectedRevision: agent.revision!, memorySettings: { approval: "auto", compilationMode: "scheduled", approvalMinimumAttemptFamilies: 2, approvalRequiredTools: ["billing.issue_refund"], }, }); ``` ## Check the learning state The learning state for a task family shows the settings that apply and the next step. | Field | Description | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | `eligible_trajectory_count` | The count of closed Trajectories that compilation can use | | `minimum_attempt_families` | The count of attempt families that compilation needs | | `compilation_pending` | `true` when a learning run waits to start or runs | | `required_evaluations` | The evaluations that candidates of this task family need | | `next_step` | The next action. For example, `Collect more eligible trajectories before compilation.` or `Await human approval before retrieval.` | The Skill candidates endpoint lists the candidates that wait for a decision. ## Learning runs Zep records the result of each compilation as a learning run. Use the learning runs to find why a task family has no new Skill. **`Python`** ```python Python for run in client.agent.learning.list_runs( agent_uuid=agent_uuid, task_family="billing.support", ): print(run.decision, run.stage, run.rejection_class, run.reason_text) ``` **`TypeScript`** ```typescript TypeScript const runs = await client.agent.learning.listRuns(agentUuid, { taskFamily: "billing.support", limit: 20, cursor: null, }); for await (const run of runs) { console.log(run.decision, run.stage, run.rejectionClass, run.reasonText); } ``` | `decision` | Meaning | | ----------- | --------------------------------------------------------------------------- | | `produced` | The run produced one or more candidates. `candidate_count` gives the count. | | `no_change` | The run found no change to make to the Skills of the task family. | | `rejected` | Zep rejected the result of the run. `rejection_class` gives the cause. | | `failed` | The run stopped because of an error. `rejection_class` gives the cause. | | `rejection_class` | Cause and action | | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `no_eligible_trajectories` | The task family has no successful Trajectories with strong verification. Capture and close more runs. | | `corroboration_insufficient` | A part of the Skill has no support from a successful attempt family with strong verification. Capture more verified runs. | | `applicability_ungrounded` | The Skill names a model, a tool, or an environment that the event `context` of the cited Trajectories does not contain. Send the event `context` when you [append events](/agent-skills/capture-trajectories#append-events). | | `scanner_rejected` | The candidate contains a value that Zep does not accept, for example a secret or a run-specific literal. See [Literal policy](#literal-policy). | | `prompt_budget_exceeded` | The evidence is too large for one compilation. Use more specific task families. | For the other rejection classes, the `reason_text` field gives the cause. ## Literal policy A literal is a concrete value in a candidate, for example a command name, an account number, or an endpoint URL. A literal that is specific to one run can make a Skill wrong for the next run. Zep scans each candidate for literals. The literal policy of the Agent controls the result. | Field | Description | | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `default` | The action for a literal that the policy does not allow. `parameterize` replaces the literal with a parameter. `remove` removes the literal. `reject` rejects the candidate. The default is `reject`. | | `allowlisted_classes` | The classes of tool and environment literals that a Skill can keep, for example `command_name` or `public_endpoint` | | `allowlisted_values` | The exact tool and environment values that a Skill can keep. Each list has a maximum of 256 values. | Zep keeps a literal only when its value and its class are both in the policy, and the Skill applies to that tool or environment. Zep always rejects a candidate that contains a secret, a credential, a token, a prompt injection, or a harmful instruction. The policy cannot change this behavior. **`Python`** ```python Python from zep_cloud import AgentLiteralPolicyClasses, AgentLiteralPolicyValues policy = client.agent.literal_policy.get(agent_uuid=agent_uuid) client.agent.literal_policy.update( agent_uuid=agent_uuid, expected_revision=policy.revision, default="parameterize", allowlisted_classes=AgentLiteralPolicyClasses( tools=["command_name"], environments=[], ), allowlisted_values=AgentLiteralPolicyValues( tools=["billing.get_payments"], environments=[], ), ) ``` **`TypeScript`** ```typescript TypeScript const policy = await client.agent.literalPolicy.get(agentUuid); await client.agent.literalPolicy.update(agentUuid, { expectedRevision: policy.revision, default: "parameterize", allowlistedClasses: { tools: ["command_name"], environments: [] }, allowlistedValues: { tools: ["billing.get_payments"], environments: [] }, }); ``` The policy applies to the candidates that Zep scans after the update. ## Breaking deployment changes A Skill can depend on the behavior of one deployment of your agent, for example the tool names of a release. When you deploy a release that changes this behavior, declare a breaking change. An ordinary Agent update does not declare a breaking change. **`Python`** ```python Python agent = client.agent.get(agent_uuid=agent_uuid) client.agent.declare_breaking_change( agent_uuid=agent_uuid, expected_revision=agent.revision, version="2026.10.0", ) ``` **`TypeScript`** ```typescript TypeScript const agent = await client.agent.get(agentUuid); await client.agent.declareBreakingChange(agentUuid, { expectedRevision: agent.revision!, version: "2026.10.0", }); ``` The `version` value must be different from the current deployment version of the Agent. Zep sets the new version and increases the Agent `revision`. Zep also removes compiled Skills from search when their applicable Agent versions do not include the new version. Skills without Agent version constraints stay in search. A removed Skill returns to search only after a compatible version of the Skill passes admission. ## Admission and publication Admission makes a Skill available to its own Agent only. To give a Skill to a different Agent, [publish the Skill](/agent-skill-publication). > Control when Zep compiles Skills and which Skills an agent can retrieve