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

# Agent Skills

> Install the Namespace Devbox agent skill so a coding agent can create, use, and clean up Devboxes.

export const KeepTabPosition = () => {
  useEffect(() => {
    const stateKey = "__namespaceKeepTabPosition";
    const releaseState = state => {
      state.instances -= 1;
      if (state.instances > 0) return;
      state.removeListeners();
      if (window[stateKey] === state) delete window[stateKey];
    };
    const existingState = window[stateKey];
    if (existingState) {
      existingState.instances += 1;
      return () => releaseState(existingState);
    }
    const maxSettleTime = 250;
    const requiredStableFrames = 3;
    const positionTolerance = 0.5;
    let animationFrame;
    let observer;
    let settleDeadline;
    let stableFrames = 0;
    let tabListToKeep;
    let tabListTop;
    const findTab = event => {
      if (!(event.target instanceof Element)) return null;
      return event.target.closest(".tab-container [role='tab']");
    };
    const findScrollContainer = element => {
      for (let parent = element.parentElement; parent; parent = parent.parentElement) {
        const {overflowY} = getComputedStyle(parent);
        if ((overflowY === "auto" || overflowY === "scroll") && parent.scrollHeight > parent.clientHeight) {
          return parent;
        }
      }
      return null;
    };
    const stopKeepingPosition = () => {
      if (animationFrame) cancelAnimationFrame(animationFrame);
      animationFrame = undefined;
      observer?.disconnect();
      tabListToKeep = undefined;
    };
    const restoreTabListPosition = () => {
      if (!tabListToKeep?.isConnected) return 0;
      const offset = tabListToKeep.getBoundingClientRect().top - tabListTop;
      if (Math.abs(offset) < positionTolerance) return offset;
      const scrollOptions = {
        top: offset,
        behavior: "instant"
      };
      const scrollContainer = findScrollContainer(tabListToKeep);
      if (scrollContainer) {
        scrollContainer.scrollBy(scrollOptions);
      } else {
        window.scrollBy(scrollOptions);
      }
      return offset;
    };
    const settlePosition = () => {
      const offset = restoreTabListPosition();
      stableFrames = Math.abs(offset) < positionTolerance ? stableFrames + 1 : 0;
      if (stableFrames >= requiredStableFrames || performance.now() >= settleDeadline) {
        stopKeepingPosition();
        return;
      }
      animationFrame = requestAnimationFrame(settlePosition);
    };
    observer = new MutationObserver(() => {
      stableFrames = 0;
      restoreTabListPosition();
    });
    const keepTabListInPlace = tab => {
      stopKeepingPosition();
      tabListToKeep = tab.closest("[role='tablist']");
      if (!tabListToKeep) return;
      tabListTop = tabListToKeep.getBoundingClientRect().top;
      settleDeadline = performance.now() + maxSettleTime;
      stableFrames = 0;
      observer.observe(document.getElementById("content") ?? document.documentElement, {
        attributes: true,
        attributeFilter: ["aria-selected", "class"],
        childList: true,
        subtree: true
      });
      animationFrame = requestAnimationFrame(settlePosition);
    };
    const selectWithoutNavigation = event => {
      if (!event.isTrusted) return;
      const tab = findTab(event);
      if (!tab) return;
      keepTabListInPlace(tab);
      event.preventDefault();
      event.stopPropagation();
      tab.click();
      restoreTabListPosition();
    };
    const selectWithKeyboard = event => {
      if (!event.isTrusted) return;
      const tab = findTab(event);
      const tabList = tab?.closest("[role='tablist']");
      if (!tab || !tabList) return;
      const tabs = Array.from(tabList.querySelectorAll(":scope > [role='tab']"));
      const currentIndex = tabs.indexOf(tab);
      let nextIndex;
      switch (event.key) {
        case "ArrowLeft":
          nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;
          break;
        case "ArrowRight":
          nextIndex = (currentIndex + 1) % tabs.length;
          break;
        case "Home":
          nextIndex = 0;
          break;
        case "End":
          nextIndex = tabs.length - 1;
          break;
        case "Enter":
        case " ":
          nextIndex = currentIndex;
          break;
        default:
          return;
      }
      keepTabListInPlace(tab);
      event.preventDefault();
      event.stopPropagation();
      tabs[nextIndex]?.click();
      tabs[nextIndex]?.focus({
        preventScroll: true
      });
      restoreTabListPosition();
    };
    document.addEventListener("click", selectWithoutNavigation, true);
    document.addEventListener("keydown", selectWithKeyboard, true);
    const state = {
      instances: 1,
      removeListeners: () => {
        stopKeepingPosition();
        document.removeEventListener("click", selectWithoutNavigation, true);
        document.removeEventListener("keydown", selectWithKeyboard, true);
      }
    };
    window[stateKey] = state;
    return () => releaseState(state);
  }, []);
  return null;
};

<KeepTabPosition />

A coding agent needs a machine where it can clone a repository, install dependencies, run commands, and return the result. An agent skill gives it a repeatable workflow for doing that on a Devbox.

Namespace publishes Devbox skills in [`namespacelabs/agent-skills`](https://github.com/namespacelabs/agent-skills). A skill is an instruction pack for coding agents. It gives the agent a repeatable workflow for creating Devboxes, loading source code, running commands, and cleaning up after the task.

For a worked example, see [Testing with Devboxes and agent skills](https://namespace.so/blog/devbox-test-with-skills).

<h2 id="install">
  Install the skill
</h2>

Install the skill in a project when you want the repository to carry the same agent instructions for everyone. Install it globally when you want to use the skill across projects from your own machine.

<Tabs>
  <Tab title="Project">
    Run this from the project directory:

    ```bash theme={null}
    npx skills add namespacelabs/agent-skills
    ```
  </Tab>

  <Tab title="Global">
    Run this once for your local agent setup:

    ```bash theme={null}
    npx skills add namespacelabs/agent-skills --global
    ```
  </Tab>
</Tabs>

<h2 id="get-started">
  Get started with an agent
</h2>

If you have never used a Devbox before, hand your agent the prompt below. It installs the skill first, so it works even if you skipped the step above, then walks the whole setup: CLI, login, a first Devbox, and how to open a shell in it.

You will need to complete the login in your browser when the agent reaches that step.

```text wrap Agent Prompt theme={null}
Install the Namespace devboxes agent skill, then use it to set me up:

  npx skills add namespacelabs/agent-skills

Following that skill:

1. Install the Devbox CLI for my operating system, then confirm it works.
2. Log me in to Devbox, then verify that the login succeeded.
3. Create a Devbox for me at size `m`. If we are working in a git repository,
   check that repository out in the Devbox so my code is already there.
4. List my Devboxes, then report the new one's name, its state, and how I can
   open a shell in it.

Do not delete or stop any Devbox that already exists in my workspace.
```

<h2 id="use">
  Use the skill
</h2>

Once the skill is installed, ask your agent for what you want in plain language and the skill supplies the commands. For anything that acts on your code, start the agent from the repository so it can see the files. The exact behavior depends on the agent and the project.

<Tabs>
  <Tab title="Log me in">
    ```text wrap Agent Prompt theme={null}
    log me in to devbox
    ```

    Logging in opens a browser. The agent hands that step to you, waits for the command to finish, then verifies the credential.
  </Tab>

  <Tab title="Create a Devbox">
    ```text wrap Agent Prompt theme={null}
    create a devbox for this repo
    ```

    The agent picks an image and size, checks the repository out, and reports the Devbox name.
  </Tab>

  <Tab title="Run a command">
    ```text wrap Agent Prompt theme={null}
    run `go build ./...` in my devbox and show me the output
    ```

    The agent uses `devbox exec`, which retains the output so it can be read again later with `devbox logs`.
  </Tab>

  <Tab title="Run tests">
    ```text wrap Agent Prompt theme={null}
    run the test suite in a devbox
    ```

    For larger suites, ask the agent to split the work across multiple Devboxes:

    ```text wrap Agent Prompt theme={null}
    run the tests in parallel devboxes
    ```

    In a typical run, the agent creates one or more Devboxes, copies the relevant source state into them, runs the requested commands, reports the result, and deletes or releases the Devboxes it used.
  </Tab>

  <Tab title="Copy local changes">
    ```text wrap Agent Prompt theme={null}
    copy my local changes to my devbox
    ```

    A Devbox with a repository checked out holds the default branch, so the agent aligns it to the same commit as your working tree before applying your uncommitted changes as a patch. Untracked files are uploaded separately, since a diff does not include them.
  </Tab>
</Tabs>

## What the skill covers

The skill instructs the agent on the whole Devbox workflow:

* Installing the Devbox CLI and logging in
* Creating a Devbox, including picking an image and size
* Loading source code and installing toolchains
* Running commands with `devbox exec`, including detached runs and their logs
* Sharing web work through `devbox.so` URLs
* Tearing the Devbox down, or leaving it running when work continues

## Next Steps

<Columns cols={3}>
  <Card title="Devbox CLI" icon="terminal" href="/docs/devbox/cli">
    Install and authenticate the CLI the skill drives.
  </Card>

  <Card title="Executing Commands" icon="play" href="/docs/devbox/exec">
    Run commands and read their retained output.
  </Card>

  <Card title="Long Running Tasks" icon="timer" href="/docs/guides/devbox/long-running-tasks">
    Keep a Devbox alive while an agent works.
  </Card>
</Columns>
