> ## Documentation Index
> Fetch the complete documentation index at: https://infisical.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Plan your Agent Vault setup

> Get a recommended Agent Vault setup for what you're building.

export const AgentVaultSetupBranch = ({building, runs, agent, model, children}) => {
  const SELECTION_EVENT = "av-setup-selection-change";
  const RULES = {
    personal: {
      model: "user",
      runs: ["computer", "server", "container"]
    },
    assistant: {
      model: "user",
      runs: ["computer", "server", "container"]
    },
    scheduled: {
      model: "job",
      runs: ["computer", "server", "container", "ci"]
    },
    platform: {
      model: "orchestrator",
      runs: ["server", "container", "ci"]
    }
  };
  const ALL_AGENTS = ["claude-code", "codex", "opencode", "hermes", "openclaw", "custom"];
  const readSelection = () => {
    const params = new URLSearchParams(window.location.search);
    const buildingId = Object.prototype.hasOwnProperty.call(RULES, params.get("building")) ? params.get("building") : "personal";
    const rule = RULES[buildingId];
    const runsId = params.get("runs");
    const agentId = params.get("agent");
    return {
      building: buildingId,
      model: rule.model,
      runs: rule.runs.includes(runsId) ? runsId : null,
      agent: ALL_AGENTS.includes(agentId) ? agentId : null
    };
  };
  const [selection, setSelection] = useState({
    building: "personal",
    model: "user",
    runs: null,
    agent: null
  });
  useEffect(() => {
    const sync = () => setSelection(readSelection());
    sync();
    window.addEventListener(SELECTION_EVENT, sync);
    window.addEventListener("popstate", sync);
    return () => {
      window.removeEventListener(SELECTION_EVENT, sync);
      window.removeEventListener("popstate", sync);
    };
  }, []);
  const matches = (wanted, current) => {
    if (wanted === undefined || wanted === null) return true;
    const list = String(wanted).split(",").map(entry => entry.trim()).filter(Boolean);
    return list.length === 0 || list.includes(current ?? "none");
  };
  if (!matches(building, selection.building) || !matches(model, selection.model) || !matches(runs, selection.runs) || !matches(agent, selection.agent)) {
    return null;
  }
  return <>{children}</>;
};

export const AgentVaultSetupSummary = () => {
  const BUILDS = {
    personal: "coding agent for yourself",
    assistant: "an always-on assistant",
    scheduled: "a scheduled or unattended job",
    platform: "a service that starts agents for tasks"
  };
  const RUNS = {
    personal: ["computer", "server", "container"],
    assistant: ["computer", "server", "container"],
    scheduled: ["computer", "server", "container", "ci"],
    platform: ["server", "container", "ci"]
  };
  const PLACES = {
    computer: "on your computer",
    server: "on a server or VM",
    container: "in a container",
    ci: "in a CI runner"
  };
  const AGENTS = {
    "claude-code": "Claude Code",
    codex: "Codex",
    opencode: "OpenCode",
    hermes: "Hermes Agent",
    openclaw: "OpenClaw",
    custom: "your own agent"
  };
  const SELECTION_EVENT = "av-setup-selection-change";
  const readSelection = () => {
    const params = new URLSearchParams(window.location.search);
    const has = (object, key) => Object.prototype.hasOwnProperty.call(object, key);
    const building = has(BUILDS, params.get("building")) ? params.get("building") : "personal";
    const runs = params.get("runs");
    const agent = params.get("agent");
    return {
      building,
      runs: RUNS[building].includes(runs) ? runs : null,
      agent: has(AGENTS, agent) ? agent : null
    };
  };
  const [selection, setSelection] = useState({
    building: "personal",
    runs: null,
    agent: null
  });
  useEffect(() => {
    const sync = () => setSelection(readSelection());
    sync();
    window.addEventListener(SELECTION_EVENT, sync);
    window.addEventListener("popstate", sync);
    return () => {
      window.removeEventListener(SELECTION_EVENT, sync);
      window.removeEventListener("popstate", sync);
    };
  }, []);
  let buildText = BUILDS[selection.building];
  if (selection.runs) {
    buildText = selection.building === "platform" ? `a service that starts agents ${PLACES[selection.runs]} for each task` : `${buildText} that runs ${PLACES[selection.runs]}`;
  }
  const agentText = selection.agent ? `, using ${AGENTS[selection.agent]}` : "";
  const missing = [];
  if (!selection.runs) missing.push("where the agent runs");
  if (!selection.agent) missing.push("which agent you use");
  return <p>
      You're building {buildText}
      {agentText}.
      
      {missing.length == 0 && ` Here's how the setup works:`}
      {missing.length > 0 && ` Choose ${missing.join(" and ")} to fill in the rest of the setup.`}
    </p>;
};

export const AgentVaultSetupStep = ({step, children}) => {
  const MODELS = {
    personal: "user",
    assistant: "user",
    scheduled: "job",
    platform: "orchestrator"
  };
  const CREATORS = {
    user: "You",
    job: "Infisical CLI",
    orchestrator: "Orchestrator"
  };
  const SELECTION_EVENT = "av-setup-selection-change";
  const readModel = () => {
    const params = new URLSearchParams(window.location.search);
    const building = params.get("building");
    return Object.prototype.hasOwnProperty.call(MODELS, building) ? MODELS[building] : "user";
  };
  const [model, setModel] = useState("user");
  useEffect(() => {
    const sync = () => setModel(readModel());
    sync();
    window.addEventListener(SELECTION_EVENT, sync);
    window.addEventListener("popstate", sync);
    return () => {
      window.removeEventListener(SELECTION_EVENT, sync);
      window.removeEventListener("popstate", sync);
    };
  }, []);
  const creator = CREATORS[model];
  const STEPS = {
    before: {},
    create: {
      number: 1,
      title: ({
        user: "You create a session",
        job: "The CLI logs in and creates a session",
        orchestrator: "The orchestrator creates a session for the task"
      })[model],
      route: `${creator} → Infisical`
    },
    token: {
      number: 2,
      title: "Infisical returns a session token",
      route: `Infisical → ${creator}`
    },
    start: {
      number: 3,
      title: ({
        user: "You start the agent with the token",
        job: "The CLI starts the agent with the token",
        orchestrator: "The orchestrator starts an agent with the token"
      })[model],
      route: `${creator} → Agent`
    },
    request: {
      number: 4,
      title: "The agent sends an API request",
      route: "Agent → API (intercepted by proxy)"
    },
    fetch: {
      number: 5,
      title: "The proxy gets the session's credentials",
      route: "Proxy → Infisical"
    },
    forward: {
      number: 6,
      title: "The proxy sends the request with the real credential",
      route: "Proxy → API"
    },
    revoke: {
      number: 7,
      title: model === "orchestrator" ? "The orchestrator revokes the session when the task ends" : "The CLI revokes the session when the agent exits",
      route: `${creator} → Infisical`
    }
  };
  const current = STEPS[step];
  if (!current || step === "revoke" && model === "user") return null;
  return <section className="ifx-avsp__walk-step" data-avsp-focus={`step-${step}`}>
      <div className="ifx-avsp__walk-head not-prose">
        {current.number ? <span className="ifx-avsp__walk-num">{current.number}</span> : null}
        <div>
          <h3 className="ifx-avsp__walk-title">{current.title}</h3>
          {current.route ? <p className="ifx-avsp__walk-route">{current.route}</p> : null}
        </div>
      </div>
      <div className="ifx-avsp__walk-body">{children}</div>
    </section>;
};

export const AgentVaultSetupDiagram = ({inline, reveal}) => {
  const RULES = {
    personal: {
      model: "user",
      runs: ["computer", "server", "container"]
    },
    assistant: {
      model: "user",
      runs: ["computer", "server", "container"]
    },
    scheduled: {
      model: "job",
      runs: ["computer", "server", "container", "ci"]
    },
    platform: {
      model: "orchestrator",
      runs: ["server", "container", "ci"]
    }
  };
  const HOSTS = {
    computer: "Your computer",
    server: "Server or VM",
    container: "Container",
    ci: "CI runner"
  };
  const FOCUS = {
    building: {
      lanes: ["infisical", "creator"],
      messages: ["create", "token", "start", "revoke"]
    },
    runs: {
      lanes: ["agent", "proxy"],
      messages: ["start", "request"]
    },
    agent: {
      lanes: ["agent"],
      messages: ["start", "request"]
    },
    "step-before": {
      lanes: ["infisical", "proxy"],
      messages: []
    }
  };
  const SELECTION_EVENT = "av-setup-selection-change";
  const AGENT_IDS = ["claude-code", "codex", "opencode", "hermes", "openclaw", "custom"];
  const readSelection = () => {
    const params = new URLSearchParams(window.location.search);
    const building = Object.prototype.hasOwnProperty.call(RULES, params.get("building")) ? params.get("building") : "personal";
    const runs = params.get("runs");
    const agent = params.get("agent");
    return {
      building,
      model: RULES[building].model,
      runs: RULES[building].runs.includes(runs) ? runs : null,
      agent: AGENT_IDS.includes(agent) ? agent : null
    };
  };
  const [selection, setSelection] = useState({
    building: "personal",
    model: "user",
    runs: null,
    agent: null
  });
  const [focus, setFocus] = useState(null);
  const buildRef = useRef(null);
  const GUIDES = "/documentation/platform/agent-vault";
  let buildHref = "#build-your-setup";
  if (selection.model === "user") {
    const guide = ({
      "claude-code": "guides/claude-code",
      codex: "guides/codex",
      opencode: "guides/opencode",
      hermes: selection.building === "assistant" ? "guides/hermes-gateway" : "guides/hermes",
      openclaw: selection.building === "assistant" ? "guides/openclaw-gateway" : "guides/openclaw",
      custom: "guides/custom-agent"
    })[selection.agent];
    buildHref = `${GUIDES}/${guide ?? "quickstart"}`;
  }
  useEffect(() => {
    const link = buildRef.current;
    if (!link) return;
    const href = link.getAttribute("href") || "";
    const underDocs = window.location.pathname === "/docs" || window.location.pathname.startsWith("/docs/");
    if (underDocs && href.startsWith("/") && !href.startsWith("/docs/")) {
      link.setAttribute("href", `/docs${href}`);
    }
  }, [buildHref]);
  useEffect(() => {
    const sync = () => setSelection(readSelection());
    sync();
    window.addEventListener(SELECTION_EVENT, sync);
    window.addEventListener("popstate", sync);
    let frame = 0;
    const onScroll = () => {
      cancelAnimationFrame(frame);
      frame = requestAnimationFrame(() => {
        const line = window.innerHeight * 0.4;
        const sections = Array.from(document.querySelectorAll("[data-avsp-focus]"));
        let current = null;
        sections.forEach(el => {
          if (el.getBoundingClientRect().top <= line) current = el;
        });
        const last = sections[sections.length - 1];
        if (current === last && last.getBoundingClientRect().bottom <= line) current = null;
        sections.forEach(el => el.toggleAttribute("data-avsp-active", el === current));
        setFocus(current ? current.getAttribute("data-avsp-focus") : null);
      });
    };
    onScroll();
    window.addEventListener("scroll", onScroll, {
      passive: true
    });
    window.addEventListener("resize", onScroll);
    return () => {
      window.removeEventListener(SELECTION_EVENT, sync);
      window.removeEventListener("popstate", sync);
      window.removeEventListener("scroll", onScroll);
      window.removeEventListener("resize", onScroll);
      cancelAnimationFrame(frame);
    };
  }, []);
  const sharesHost = selection.model === "job";
  const creator = ({
    user: {
      label: "You",
      sub: "Infisical dashboard"
    },
    job: {
      label: "Infisical CLI",
      sub: "Machine identity"
    },
    orchestrator: {
      label: "Orchestrator",
      sub: "Machine identity"
    }
  })[selection.model];
  const lanes = [{
    id: "infisical",
    label: "Infisical",
    sub: "Cloud or self-hosted"
  }, {
    id: "creator",
    label: creator.label,
    sub: creator.sub
  }, {
    id: "agent",
    label: "Agent",
    sub: selection.runs ? HOSTS[selection.runs] : "Agent's host"
  }, {
    id: "proxy",
    label: "Proxy",
    sub: "Its own host"
  }, {
    id: "api",
    label: "API",
    sub: "Such as GitHub"
  }];
  const laneIndex = id => lanes.findIndex(lane => lane.id === id);
  const messages = [{
    id: "create",
    from: "creator",
    to: "infisical",
    label: ({
      user: "Create a session",
      job: "Log in and create a session",
      orchestrator: "Create a session for the task"
    })[selection.model]
  }, {
    id: "token",
    from: "infisical",
    to: "creator",
    label: "Session token",
    reply: true
  }, {
    id: "start",
    from: "creator",
    to: "agent",
    label: selection.model === "orchestrator" ? "Start an agent with the token" : "Start the agent with the token"
  }, {
    id: "request",
    from: "agent",
    to: "proxy",
    label: "API request",
    note: "(e.g. api.github.com)",
    aimedAt: "api"
  }, {
    id: "fetch",
    from: "proxy",
    to: "infisical",
    label: "Get the session's credentials"
  }, {
    id: "forward",
    from: "proxy",
    to: "api",
    label: "Request with the real credential"
  }];
  if (selection.model === "job") {
    messages.push({
      id: "revoke",
      from: "creator",
      to: "infisical",
      label: "Revoke the session when the agent exits"
    });
  }
  if (selection.model === "orchestrator") {
    messages.push({
      id: "revoke",
      from: "creator",
      to: "infisical",
      label: "Revoke the session when the task ends"
    });
  }
  const scrollToStep = id => {
    const block = document.querySelector(`[data-avsp-focus="step-${id}"]`);
    if (!block) return;
    const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    block.scrollIntoView({
      behavior: reduceMotion ? "auto" : "smooth",
      block: "center"
    });
  };
  let highlight = null;
  if (focus) {
    const stepMessage = messages.find(message => `step-${message.id}` === focus);
    highlight = stepMessage ? {
      lanes: [stepMessage.from, stepMessage.to],
      messages: [stepMessage.id]
    } : FOCUS[focus] ?? null;
  }
  const stateClass = (base, active) => {
    if (!highlight) return base;
    return active ? `${base} ${base}--focus` : `${base} ${base}--dim`;
  };
  let revealed = null;
  if (reveal) {
    let stage = 0;
    if (focus === null) {
      stage = messages.length;
    } else if (focus.startsWith("step-") && focus !== "step-before") {
      stage = messages.findIndex(message => `step-${message.id}` === focus) + 1;
    }
    const shown = messages.slice(0, stage);
    const current = focus && focus.startsWith("step-") && stage > 0 ? shown[stage - 1] : null;
    const shownLanes = new Set(["infisical", "proxy"]);
    shown.forEach(message => {
      shownLanes.add(message.from);
      shownLanes.add(message.to);
      if (message.aimedAt) shownLanes.add(message.aimedAt);
    });
    revealed = {
      shown: new Set(shown.map(message => message.id)),
      shownLanes,
      current
    };
  }
  const laneClass = id => {
    if (!revealed) return stateClass("ifx-avsp__lane", highlight && highlight.lanes.includes(id));
    if (!revealed.shownLanes.has(id)) return "ifx-avsp__lane ifx-avsp__lane--hidden";
    const focused = revealed.current ? [revealed.current.from, revealed.current.to].includes(id) : focus === "step-before";
    return focused ? "ifx-avsp__lane ifx-avsp__lane--focus" : "ifx-avsp__lane";
  };
  const messageClass = id => {
    if (!revealed) {
      return stateClass("ifx-avsp__message", highlight && highlight.messages.includes(id));
    }
    if (!revealed.shown.has(id)) return "ifx-avsp__message ifx-avsp__message--hidden";
    if (!revealed.current) return "ifx-avsp__message";
    return revealed.current.id === id ? "ifx-avsp__message ifx-avsp__message--focus" : "ifx-avsp__message ifx-avsp__message--past";
  };
  const lifelineClass = id => revealed && !revealed.shownLanes.has(id) ? "ifx-avsp__lifeline ifx-avsp__lifeline--hidden" : "ifx-avsp__lifeline";
  const laneCount = lanes.length;
  const center = index => `${(index + 0.5) / laneCount * 100}%`;
  return <div className={inline ? "ifx-avsp__diagram-inline not-prose" : "not-prose"}>
      <div className="ifx-avsp__panel-head">
        <a ref={buildRef} href={buildHref} className="ifx-btn ifx-btn--primary ifx-avsp__build-button">
          Build
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <path d="M5 12h14" />
            <path d="m12 5 7 7-7 7" />
          </svg>
        </a>
      </div>
      <div className="ifx-avsp__diagram-scroll">
        {}
        <div className="ifx-avsp__diagram" role="group" aria-label="Setup diagram">
          <div className="ifx-avsp__lanes" aria-hidden="true">
            {sharesHost && (!revealed || revealed.shownLanes.has("creator")) && <div className="ifx-avsp__boundary">
                <span className="ifx-avsp__boundary-label">Same host</span>
              </div>}
            {lanes.map(lane => <div key={lane.id} className={laneClass(lane.id)}>
                <span className="ifx-avsp__lane-label">{lane.label}</span>
                <span className="ifx-avsp__lane-sub">{lane.sub}</span>
              </div>)}
          </div>
          <div className="ifx-avsp__messages">
            {lanes.map((lane, index) => <span key={lane.id} className={lifelineClass(lane.id)} style={{
    left: center(index)
  }} aria-hidden="true" />)}
            {messages.map((message, index) => {
    const from = laneIndex(message.from);
    const to = laneIndex(message.to);
    const start = Math.min(from, to);
    const span = Math.abs(to - from);
    const classes = ["ifx-avsp__arrow"];
    classes.push(to > from ? "ifx-avsp__arrow--right" : "ifx-avsp__arrow--left");
    if (message.reply) classes.push("ifx-avsp__arrow--reply");
    if (message.aimedAt) classes.push("ifx-avsp__arrow--caught");
    if (start === 0) classes.push("ifx-avsp__arrow--first-lane"); else if (start + span === laneCount - 1) classes.push("ifx-avsp__arrow--last-lane");
    return <div key={message.id} className={`${messageClass(message.id)}${message.note ? " ifx-avsp__message--noted" : ""}`}>
                  <div className={classes.join(" ")} style={{
      left: center(start),
      width: `${span / laneCount * 100}%`
    }}>
                    <span className="ifx-avsp__arrow-label">
                      <button type="button" className="ifx-avsp__arrow-num ifx-avsp__arrow-num--link" aria-label={`Go to step ${index + 1}: ${message.label}`} onClick={() => scrollToStep(message.id)}>
                        {index + 1}
                      </button>
                      <span aria-hidden="true">{message.label}</span>
                    </span>
                    {message.note && <span className="ifx-avsp__arrow-note" aria-hidden="true">
                        {message.note}
                      </span>}
                    {message.aimedAt && <>
                        <span className="ifx-avsp__arrow-catch" aria-hidden="true" />
                        <span className="ifx-avsp__arrow-aim" style={{
      width: `calc(${(laneIndex(message.aimedAt) - to) / span * 100}% - 4px)`
    }} aria-hidden="true" />
                      </>}
                  </div>
                </div>;
  })}
          </div>
        </div>
      </div>
    </div>;
};

export const AgentVaultSetupQuestions = () => {
  const docsPath = typeof window === "undefined" ? "" : window.location.pathname;
  const docsBase = docsPath === "/docs" || docsPath.startsWith("/docs/") ? "/docs" : "";
  const AGENT_IMG_BASE = "/images/agent-vault-agents";
  const AGENT_IMAGES = {
    "claude-code": {
      dark: "claude-code.svg"
    },
    codex: {
      light: "OpenAI.png",
      dark: "OpenAIWhite.png"
    },
    hermes: {
      light: "hermes.png",
      dark: "hermes.on-dark.png"
    },
    opencode: {
      light: "opencode.svg",
      dark: "opencode.on-dark.svg"
    },
    openclaw: {
      dark: "openclaw.svg"
    }
  };
  const BUILDS = [{
    id: "personal",
    label: "A coding agent for yourself",
    example: "An agent that you work alongside, on your computer or a dev box.",
    runs: ["computer", "server", "container"]
  }, {
    id: "assistant",
    label: "An always-on assistant",
    example: "An agent that keeps running and answers messages, such as a chat bot.",
    runs: ["computer", "server", "container"]
  }, {
    id: "scheduled",
    label: "A scheduled or unattended job",
    example: "An agent that runs on a schedule or in CI, such as one that triages new issues.",
    runs: ["computer", "server", "container", "ci"]
  }, {
    id: "platform",
    label: "A service that starts agents for tasks",
    example: "Your own service that starts a separate agent for each task it receives.",
    runs: ["server", "container", "ci"]
  }];
  const RUNS = [{
    id: "computer",
    label: "Your computer",
    example: "Your laptop or desktop."
  }, {
    id: "server",
    label: "A server or VM",
    example: "Such as a dev box, a cloud VM, or a home server."
  }, {
    id: "container",
    label: "A container",
    example: "Such as a Docker container or a dev container."
  }, {
    id: "ci",
    label: "A CI runner",
    example: "Such as a GitHub Actions job."
  }];
  const AGENTS = [{
    id: "claude-code",
    label: "Claude Code"
  }, {
    id: "codex",
    label: "Codex"
  }, {
    id: "opencode",
    label: "OpenCode"
  }, {
    id: "hermes",
    label: "Hermes Agent"
  }, {
    id: "openclaw",
    label: "OpenClaw"
  }, {
    id: "custom",
    label: "Your own agent"
  }];
  const SELECTION_EVENT = "av-setup-selection-change";
  const readSelection = () => {
    const params = new URLSearchParams(window.location.search);
    const build = BUILDS.find(option => option.id === params.get("building")) ?? BUILDS[0];
    const runs = RUNS.find(option => option.id === params.get("runs"));
    const agent = AGENTS.find(option => option.id === params.get("agent"));
    return {
      building: build.id,
      runs: runs && build.runs.includes(runs.id) ? runs.id : null,
      agent: agent ? agent.id : null
    };
  };
  const [selection, setSelection] = useState({
    building: "personal",
    runs: null,
    agent: null
  });
  useEffect(() => {
    const sync = () => setSelection(readSelection());
    sync();
    window.addEventListener(SELECTION_EVENT, sync);
    window.addEventListener("popstate", sync);
    return () => {
      window.removeEventListener(SELECTION_EVENT, sync);
      window.removeEventListener("popstate", sync);
    };
  }, []);
  const choose = (dimension, value) => {
    const toggledOff = dimension !== "building" && selection[dimension] === value;
    const next = {
      ...selection,
      [dimension]: toggledOff ? null : value
    };
    if (dimension === "building") {
      const build = BUILDS.find(option => option.id === next.building);
      if (next.runs && !build.runs.includes(next.runs)) next.runs = null;
    }
    const params = new URLSearchParams(window.location.search);
    ["building", "runs", "agent"].forEach(key => {
      if (next[key]) params.set(key, next[key]); else params.delete(key);
    });
    const query = params.toString();
    window.history.replaceState({}, "", `${window.location.pathname}${query ? `?${query}` : ""}${window.location.hash}`);
    window.dispatchEvent(new Event(SELECTION_EVENT));
  };
  const activeBuild = BUILDS.find(option => option.id === selection.building);
  const visibleRuns = RUNS.filter(option => activeBuild.runs.includes(option.id));
  const renderAgentIcon = id => {
    if (id === "custom") {
      return <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
          <path d="m16 18 6-6-6-6" />
          <path d="m8 6-6 6 6 6" />
        </svg>;
    }
    const image = AGENT_IMAGES[id];
    const src = file => `${docsBase}${AGENT_IMG_BASE}/${encodeURIComponent(file)}`;
    const lightFile = image.light ?? image.dark;
    const darkFile = image.dark ?? image.light;
    if (lightFile === darkFile) {
      return <img src={src(lightFile)} alt="" className="ifx-avqs__img" />;
    }
    return <>
        <img src={src(lightFile)} alt="" className="ifx-avqs__img ifx-avqs__img--light-only" />
        <img src={src(darkFile)} alt="" className="ifx-avqs__img ifx-avqs__img--dark-only" />
      </>;
  };
  const renderOption = (dimension, option, children) => {
    const active = selection[dimension] === option.id;
    return <button key={option.id} type="button" aria-pressed={active} className={active ? "ifx-avsp__card ifx-avsp__card--active" : "ifx-avsp__card"} onClick={() => choose(dimension, option.id)}>
        {children}
      </button>;
  };
  return <div className="ifx-avsp__questions not-prose">
      <section className="ifx-avsp__step" data-avsp-focus="building">
        <h2 className="ifx-avsp__step-title">What are you building?</h2>
        <p className="ifx-avsp__step-desc">
          Your answer decides who creates each session and how long each session lasts.
        </p>
        <div className="ifx-avsp__cards">
          {BUILDS.map(option => renderOption("building", option, <>
                <span className="ifx-avsp__card-label">{option.label}</span>
                <span className="ifx-avsp__card-desc">{option.example}</span>
              </>))}
        </div>
      </section>

      <section className="ifx-avsp__step" data-avsp-focus="runs">
        <h2 className="ifx-avsp__step-title">
          {activeBuild.id === "platform" ? "Where do the agents run?" : "Where does the agent run?"}
        </h2>
        <p className="ifx-avsp__step-desc">
          Your answer decides where to run the proxy and how the agent starts.
        </p>
        <div className="ifx-avsp__cards">
          {visibleRuns.map(option => renderOption("runs", option, <>
                <span className="ifx-avsp__card-label">{option.label}</span>
                <span className="ifx-avsp__card-desc">{option.example}</span>
              </>))}
        </div>
      </section>

      <section className="ifx-avsp__step" data-avsp-focus="agent">
        <h2 className="ifx-avsp__step-title">Which agent?</h2>
        <p className="ifx-avsp__step-desc">
          Your answer decides which guide to follow and which command starts the agent.
        </p>
        <div className="ifx-avsp__cards">
          {AGENTS.map(option => renderOption("agent", option, <span className="ifx-avsp__card-agent">
                <span className="ifx-avsp__card-icon">{renderAgentIcon(option.id)}</span>
                <span className="ifx-avsp__card-label">{option.label}</span>
              </span>))}
        </div>
      </section>
    </div>;
};

export const AgentVaultSetupLayout = ({aside, children}) => <div className="ifx-avsp__layout">
    <div className="ifx-avsp__content">{children}</div>
    <aside className="ifx-avsp__aside">
      <div className="ifx-avsp__aside-inner">{aside}</div>
    </aside>
  </div>;

export const AgentVaultSetupPage = ({eyebrow, title, description, children}) => {
  const rootRef = useRef(null);
  useEffect(() => {
    const navbar = document.getElementById("navbar");
    if (rootRef.current && navbar) {
      rootRef.current.style.setProperty("--avsp-top", `${Math.round(navbar.getBoundingClientRect().height)}px`);
    }
  }, []);
  return <div className="ifx-avsp" ref={rootRef}>
      {}
      <header className="ifx-avsp__hero">
        {eyebrow ? <div className="ifx-avsp__eyebrow">{eyebrow}</div> : null}
        <h1 className="ifx-avsp__title">{title}</h1>
        {description ? <div className="ifx-avsp__description">{description}</div> : null}
      </header>
      {}
      <div className="ifx-avsp__body prose dark:prose-invert">{children}</div>
    </div>;
};

<AgentVaultSetupPage eyebrow="Get started" title="Plan your Agent Vault setup" description="Get a recommended Agent Vault setup for what you're building.">
  Configure the following options to get custom guidance and best practices tailored to your agent's setup.

  <AgentVaultSetupLayout aside={<AgentVaultSetupDiagram />}>
    <AgentVaultSetupQuestions />

    <AgentVaultSetupDiagram inline />
  </AgentVaultSetupLayout>

  ## Your setup

  <AgentVaultSetupSummary />

  <AgentVaultSetupLayout aside={<AgentVaultSetupDiagram reveal />}>
    <AgentVaultSetupStep step="before">
      Before running an agent, you set up two things:

      <ul>
        <li>An [access bundle](/docs/documentation/platform/agent-vault/access-bundles) in Infisical: a list of the [services](/docs/documentation/platform/agent-vault/services) (the APIs) that the agent can call, each with its real credential</li>
        <li>A running [proxy](/docs/documentation/platform/agent-vault/proxies): a program on its own machine that every request from the agent goes through</li>
      </ul>

      <AgentVaultSetupBranch building="scheduled,platform">
        <Note>
          One proxy stays running and handles the requests from every agent and every job, so you don't need a separate proxy for each job or each host.
        </Note>
      </AgentVaultSetupBranch>
    </AgentVaultSetupStep>

    <AgentVaultSetupStep step="create">
      A [session](/docs/documentation/platform/agent-vault/sessions) gives an agent access to the services in one access bundle, until the session expires or someone [revokes it](/docs/documentation/platform/agent-vault/sessions#revoke-a-session).

      <AgentVaultSetupBranch building="personal">
        You [create the session in the Infisical dashboard](/docs/documentation/platform/agent-vault/sessions#create-a-session).
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="assistant">
        You [create one session in the Infisical dashboard](/docs/documentation/platform/agent-vault/sessions#create-a-session) that never expires, since the assistant keeps running.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="scheduled">
        Each time the job runs, the [Infisical CLI](/docs/cli/overview) logs in as a [machine identity](/docs/documentation/platform/identities/machine-identities) and creates a session. [Each session lasts](/docs/documentation/platform/agent-vault/sessions-cli#choose-how-long-each-session-lasts) a little longer than the longest run you expect, because the agent loses access to the APIs if a run outlasts its session.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="platform">
        For each task, the orchestrator logs in as a [machine identity](/docs/documentation/platform/identities/machine-identities) and creates a session through the [Infisical API](/docs/api-reference/endpoints/agent-vault-sessions/create). Each kind of task has its own access bundle, and the orchestrator chooses the access bundle when it creates the session.
      </AgentVaultSetupBranch>
    </AgentVaultSetupStep>

    <AgentVaultSetupStep step="token">
      The session token only works for the services in the session's access bundle, and only until the session expires or is revoked.

      <AgentVaultSetupBranch building="personal,assistant">
        The dashboard shows the token in a command that starts the agent with it.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="assistant">
        Because the session never expires, revoking it is what stops the assistant from using the real credentials.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="scheduled">
        The CLI keeps the token and passes it to the agent in the next step, so you never handle the token yourself.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="platform">
        The orchestrator receives the token in the API response.
      </AgentVaultSetupBranch>
    </AgentVaultSetupStep>

    <AgentVaultSetupStep step="start">
      The agent gets the session token instead of real API keys. [`infisical agent-vault run`](/docs/cli/reference#agent-vault-run) starts the agent with its requests set to go through the proxy.

      <AgentVaultSetupBranch building="personal,assistant">
        You run the command from the dashboard on the agent's host.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="scheduled">
        The CLI starts the agent right after it creates the session. The agent can read the machine identity's credentials [from its environment](/docs/documentation/platform/agent-vault/sessions-cli#step-2-start-the-agent), and could use them to create a session for any access bundle the machine identity has. That's why the machine identity only has the access bundle that this agent uses.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="platform">
        The orchestrator starts the agent on a different host and passes it only the session token. The orchestrator stays off the agents' hosts because the machine identity it uses can create sessions for every access bundle it's granted. An agent that read those credentials could reach every service in those access bundles.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="scheduled,platform" agent="claude-code">
        Nobody is at the terminal while the agent runs, so Claude Code runs in its [non-interactive mode](https://code.claude.com/docs/en/headless): `claude -p "<prompt>"`.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="scheduled,platform" agent="codex">
        Nobody is at the terminal while the agent runs, so Codex runs in its [non-interactive mode](https://developers.openai.com/codex/noninteractive): `codex exec "<prompt>"`.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="scheduled,platform" agent="opencode">
        Nobody is at the terminal while the agent runs, so OpenCode runs in its [non-interactive mode](https://opencode.ai/docs/cli/#run-1): `opencode run "<prompt>"`.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="scheduled,platform" agent="hermes">
        Nobody is at the terminal while the agent runs, so Hermes runs in its [non-interactive mode](https://hermes-agent.nousresearch.com/docs/user-guide/cli): `hermes chat -q "<prompt>"`.

        <Note> Hermes won't start without the API keys in `~/.hermes/.env`, so that file holds [placeholder values](/docs/documentation/platform/agent-vault/guides/hermes#step-2-launch-your-agent), and the proxy attaches the real keys.</Note>
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="scheduled,platform" agent="openclaw">
        Nobody is at the terminal while the agent runs, so OpenClaw runs in its [non-interactive mode](https://docs.openclaw.ai/cli/agent): `openclaw agent --agent <agent-id> --message "<prompt>" --local`. OpenClaw holds a [placeholder](/docs/documentation/platform/agent-vault/guides/openclaw#step-2-launch-your-agent) instead of your model provider's key, and the proxy attaches the real key.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch runs="computer">
        <Warning>
          The agent runs as your user account. If you're logged in to the [Infisical CLI](/docs/cli/overview) on the same computer, the agent can run Infisical CLI commands with your login.
        </Warning>
      </AgentVaultSetupBranch>
    </AgentVaultSetupStep>

    <AgentVaultSetupStep step="request">
      The agent calls an API the same way it always does, but the request is intercepted by the proxy.

      <ul>
        <AgentVaultSetupBranch runs="computer">
          <li>If you don't have a second machine, a small VM on your network can run the proxy</li>
        </AgentVaultSetupBranch>

        <AgentVaultSetupBranch runs="container">
          <li>The agents' containers don't have access to the proxy's state directory</li>
        </AgentVaultSetupBranch>

        <AgentVaultSetupBranch runs="ci">
          <li>The CI runner has to reach the proxy, so if the proxy is on a private network, the job runs on a [self-hosted runner](https://docs.github.com/en/actions/hosting-your-own-runners) in that network</li>
        </AgentVaultSetupBranch>
      </ul>

      <Note>
        The proxy [runs on a different machine](/docs/documentation/platform/agent-vault/proxies#choose-where-to-run-the-proxy) from the agent, on the same private network. If the proxy ran on the agent's machine, the agent could read the proxy's [state directory](/docs/documentation/platform/agent-vault/proxies#state-directory), which holds the proxy's access token.
      </Note>
    </AgentVaultSetupStep>

    <AgentVaultSetupStep step="fetch">
      The credentials go from Infisical to the proxy, never to the agent. The proxy checks Infisical for updated values every [poll interval](/docs/documentation/platform/agent-vault/proxies#poll-interval) (60 seconds by default).
    </AgentVaultSetupStep>

    <AgentVaultSetupStep step="forward">
      The [real credential](/docs/documentation/platform/agent-vault/services#credential-types) is added to the request at the proxy, so it never passes through the agent. If you've [set up session logs](/docs/documentation/platform/agent-vault/session-logs#setting-up-session-logs), the request appears in the session's logs.

      The proxy only attaches credentials for the services in the access bundle. Requests to any other host go out without a credential, unless the proxy's [traffic policy](/docs/documentation/platform/agent-vault/proxies#traffic-policy) blocks them.
    </AgentVaultSetupStep>

    <AgentVaultSetupStep step="revoke">
      <AgentVaultSetupBranch building="scheduled">
        From then on, the session token stops working. If the machine shuts down before the CLI can revoke the session, the session keeps working until its `--ttl` runs out.
      </AgentVaultSetupBranch>

      <AgentVaultSetupBranch building="platform">
        The orchestrator revokes the session through the [Infisical API](/docs/api-reference/endpoints/agent-vault-sessions/revoke).
      </AgentVaultSetupBranch>
    </AgentVaultSetupStep>
  </AgentVaultSetupLayout>

  <div id="build-your-setup" className="ifx-avsp__anchor" />

  ## Build your setup

  Follow these pages in order:

  <ol>
    <AgentVaultSetupBranch building="personal,assistant" agent="none">
      <li>[Quickstart](/docs/documentation/platform/agent-vault/quickstart): create an access bundle, enroll a proxy, create a session, and start your agent with the session token</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="personal,assistant" agent="claude-code">
      <li>[Agent Vault with Claude Code](/docs/documentation/platform/agent-vault/guides/claude-code): create an access bundle, enroll a proxy, create a session, and start Claude Code with the session token</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="personal,assistant" agent="codex">
      <li>[Agent Vault with Codex](/docs/documentation/platform/agent-vault/guides/codex): create an access bundle, enroll a proxy, create a session, and start Codex with the session token</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="personal,assistant" agent="opencode">
      <li>[Agent Vault with OpenCode](/docs/documentation/platform/agent-vault/guides/opencode): create an access bundle, enroll a proxy, create a session, and start OpenCode with the session token</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="personal" agent="hermes">
      <li>[Agent Vault with Hermes Agent](/docs/documentation/platform/agent-vault/guides/hermes): create an access bundle, enroll a proxy, create a session, and start Hermes in your terminal with the session token</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="personal" agent="openclaw">
      <li>[Agent Vault with OpenClaw](/docs/documentation/platform/agent-vault/guides/openclaw): create an access bundle, enroll a proxy, create a session, and start OpenClaw in your terminal with the session token</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="assistant" agent="hermes">
      <li>[Agent Vault with the Hermes gateway](/docs/documentation/platform/agent-vault/guides/hermes-gateway): create a session that never expires, then send the Hermes gateway's requests through the proxy</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="assistant" agent="openclaw">
      <li>[Agent Vault with the OpenClaw gateway](/docs/documentation/platform/agent-vault/guides/openclaw-gateway): create a session that never expires, then send the OpenClaw gateway's requests through the proxy</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="personal,assistant" agent="custom">
      <li>[Connect your own agent](/docs/documentation/platform/agent-vault/guides/custom-agent): create an access bundle, enroll a proxy, create a session, and send your agent's requests through the proxy</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="scheduled,platform">
      <li>[Create an access bundle](/docs/documentation/platform/agent-vault/access-bundles#create-an-access-bundle), with a service for each API the agent calls</li>
      <li>[Enroll a proxy](/docs/documentation/platform/agent-vault/proxies#create-and-enroll-a-proxy), and run it with Docker or systemd so that it keeps running between jobs</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="scheduled" runs="none,computer,server">
      <li>[Create sessions with the CLI](/docs/documentation/platform/agent-vault/sessions-cli): set up a machine identity, then run the agent from cron or systemd</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="scheduled" runs="container">
      <li>[Create sessions with the CLI](/docs/documentation/platform/agent-vault/sessions-cli): set up a machine identity, then start the agent from the container's entrypoint</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="scheduled" runs="ci">
      <li>[Create sessions with the CLI](/docs/documentation/platform/agent-vault/sessions-cli): set up a machine identity, then start the agent in a GitHub Actions step</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="platform">
      <li>[Create sessions with the API](/docs/documentation/platform/agent-vault/sessions-api): set up a machine identity for the orchestrator, then create a session for each task and revoke it when the task ends</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="platform" agent="none,claude-code,codex,opencode,hermes,openclaw">
      <li>[Start each agent with its session token](/docs/documentation/platform/agent-vault/sessions-api#step-4-start-the-agent-with-the-session-token): install the Infisical CLI on each agent's host, and start the agent with `infisical agent-vault run --session-token`</li>
    </AgentVaultSetupBranch>

    <AgentVaultSetupBranch building="scheduled,platform" agent="custom">
      <li>[Send your agent's requests through the proxy](/docs/documentation/platform/agent-vault/guides/custom-agent#step-4-send-requests-through-the-proxy): set the proxy and the proxy's certificate in your agent's HTTP client</li>
    </AgentVaultSetupBranch>
  </ol>

  <AgentVaultSetupBranch building="assistant" agent="none,claude-code,codex,opencode,custom">
    <Note>
      When the guide has you create a session, set **Expires** to **Never**. The assistant keeps running, so a session that expires would cut off its access to the APIs.
    </Note>
  </AgentVaultSetupBranch>
</AgentVaultSetupPage>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.