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

# Search, Replace, And Watch

> Search file contents, match file names, replace text, and watch directories.

## Search file names

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  matches = machine.files.search_files("/workspace", "*.py")
  for path in matches:
      print(path)
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace machine file search mch_123 /workspace "*.py"
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  curl -X POST "${NULLSPACE_API_URL}/v1/machines/mch_123/files/search" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{"path": "/workspace", "pattern": "*.py"}'
  ```
</CodeGroup>

## Search file contents

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  for match in machine.files.find_files("/workspace", "TODO"):
      print(match.file, match.line, match.content)
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace machine file find mch_123 /workspace "TODO"
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  curl -X POST "${NULLSPACE_API_URL}/v1/machines/mch_123/files/find" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{"path": "/workspace", "pattern": "TODO"}'
  ```
</CodeGroup>

## Replace text

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  paths = machine.files.search_files("/workspace", "*.py")
  replacements = machine.files.replace_in_files(
      paths,
      "old_function",
      "new_function",
  )
  print(replacements)
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace machine file replace mch_123 old_function new_function /workspace/app.py
  ```

  ```bash HTTP API theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  curl -X POST "${NULLSPACE_API_URL}/v1/machines/mch_123/files/replace" \
    -H "Authorization: Bearer ${NULLSPACE_API_KEY}" \
    -H "Content-Type: application/json" \
    -d '{"files": ["/workspace/app.py"], "pattern": "old_function", "replacement": "new_function"}'
  ```
</CodeGroup>

## Watch a directory

<CodeGroup>
  ```python Python SDK theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  def on_event(event) -> None:
      print(event.type, event.event_type, event.path)

  with machine.files.watch_dir("/workspace", on_event=on_event, recursive=True):
      machine.files.write("/workspace/changed.txt", "changed\n")
  ```

  ```bash CLI theme={"theme":{"light":"one-light","dark":"one-dark-pro"}}
  nullspace machine file watch mch_123 /workspace --recursive --timeout 30
  ```
</CodeGroup>

Directory watch is not a plain REST call: it streams change events over the
machine control WebSocket rather than a single request/response endpoint, so
there is no `curl` equivalent.

`watch_dir` calls `on_event` for file changes and returns a handle with
`stop()`. `recursive=True` watches nested directories, and `timeout=` can bound
how long the watch stays open. The CLI streams watch events as JSON lines.

## Related

* [WebSocket protocol](../reference/websocket-protocol)
* [Git helpers](../reference/git)
* [Commands](../commands/overview)
