# Cómo editar vídeo con Claude, Codex o cualquier agente de IA

> Pásale al agente una transcripción con el inicio y el final exactos de cada palabra. El agente elige qué frases dejar y un pequeño script usa esos tiempos para cortar el vídeo con ffmpeg. La API de KolWrite genera esta transcripción para audio y vídeo en 100 idiomas, y puedes aprovechar esas mismas palabras para crear los subtítulos del montaje final.

Última actualización: 2026-10-18 · HTML: https://console.kolwrite.com/es/guides/video-editing-with-ai

## Qué puede hacer el agente y qué no

Como la transcripción solo recoge lo que se habla, el agente edita guiándose por el texto. Puede quitar frases que se cortan al empezar, muletillas, tomas repetidas, rodeos o silencios largos, o bien sacar las frases exactas para un clip corto. Lo que no hace es ver el vídeo. Qué plano mostrar lo sigues decidiendo tú, a menos que le pases fotogramas para que los revise.

Si el agente puede ejecutar comandos (como Claude Code, Codex CLI o un agente de Cursor), se encarga él mismo de llamar a la API y lanzar ffmpeg. Un chat que no ejecute código no puede hacerlo, pero sí escribirte estos scripts.

## El prompt para tu agente

Con este prompt el agente trabaja con números de tramo en vez de escribir marcas de tiempo. Así evitas que se invente los tiempos. Además, enlaza directamente a la documentación de la API pensada para máquinas.

```text
Edit talk.mp4 down to the parts worth keeping, using the KolWrite API for the transcript.
Read https://console.kolwrite.com/agent-instructions.md first. The key is in KOLWRITE_API_KEY.
1. Extract the audio with ffmpeg and transcribe it with model "oracle", output_format "json", word_timestamps true.
2. Print the segments as numbered lines: S<number> [start-end] text.
3. Choose the segments to keep (remove false starts, filler, repeated takes and tangents) and write
   their numbers to keep.json as {"keep": [0, 2, 4]}. Do not invent timestamps; use segment numbers only.
4. Cut the video from those segments' word times with ffmpeg and write edited.mp4.
5. Make edited.srt for the edited video and attach it as a subtitle track.
Show me the list of removed segments before you cut anything.
```

Si quieres dejar configurada la API para cualquier sesión, añade la regla de la [guía de la herramienta](https://console.kolwrite.com/es/guides/transcription-tool-for-ai-agents) a tu archivo `AGENTS.md` o `CLAUDE.md`.

## Paso 1: extrae el audio y transcríbelo

Las subidas firmadas admiten archivos de hasta 100 MiB. Si el vídeo es largo, saca primero la pista de audio. Una hora en mono a 48 kbit/s ocupa unos 21 MB.

```bash
ffmpeg -i talk.mp4 -vn -ac 1 -ar 16000 -b:a 48k talk.mp3
```

Esta función sube un archivo local, lanza la tarea y espera a que termine:

kolwrite.py

```python
# kolwrite.py — three small functions around the KolWrite REST API
import os, time, requests

API = "https://app.kolwrite.com"
HEADERS = {"x-api-key": os.environ["KOLWRITE_API_KEY"]}


def upload(path):
    """Upload a local file (up to 100 MiB) and return a URL the API can read."""
    name = os.path.basename(path)
    form = requests.post(f"{API}/upload", headers=HEADERS, json={"filename": name}, timeout=30)
    form.raise_for_status()
    form = form.json()
    with open(path, "rb") as media:
        # No x-api-key on this request: it goes to the storage address.
        sent = requests.post(form["uploadUrl"], data=form["uploadFields"],
                             files={"file": (name, media)}, timeout=600)
    sent.raise_for_status()
    return form["fileUrl"]


def transcribe(audio_url, timeout_s=3600, **options):
    """Start a job, wait for it, return the result: a dict for json, a string for srt and txt."""
    body = {"audio_url": audio_url, "model": "oracle", **options}
    job = requests.post(f"{API}/transcribe", headers=HEADERS, json=body, timeout=30)
    job.raise_for_status()
    job_id = job.json()["jobId"]
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        time.sleep(5)
        reply = requests.get(f"{API}/transcribe/{job_id}", headers=HEADERS, timeout=30)
        reply.raise_for_status()
        reply = reply.json()
        if reply["status"] == "COMPLETED":
            return reply["result"]
        if reply["status"] == "FAILED":
            raise RuntimeError(reply.get("error", "transcription failed"))
    raise TimeoutError(f"job {job_id} did not finish in {timeout_s} seconds")
```

El script `edit.py` que verás más abajo pide el resultado en JSON y con marcas de tiempo por palabra (son las opciones por defecto, pero las dejamos puestas para que se vea claro). Devuelve una lista `segments[]`, donde cada elemento incluye `start`, `end`, `text`, `words[]` y, de forma opcional, `speaker`:

Respuesta de ejemplo (resumida):

```json
{
  "jobId": "34c63d45-4cb5-473b-bc60-25c175e69c57",
  "status": "COMPLETED",
  "result": {
    "language": "en",
    "segments": [
      {
        "start": 1.0,
        "end": 3.75,
        "text": "Hello everyone and welcome to the show.",
        "speaker": "Speaker 1",
        "words": [
          { "start": 1.0, "end": 1.35, "word": "Hello" },
          { "start": 1.4, "end": 1.75, "word": "everyone" }
        ]
      }
    ]
  }
}
```

## Paso 2: deja que el agente elija qué conservar

Saca la transcripción como una lista de líneas numeradas. Esto es lo que leerá el agente y gasta muchos menos tokens que pasarle todo el JSON con el detalle de cada palabra.

view.py

```python
# view.py — print the transcript the way an agent can read it
import json, sys

result = json.load(open(sys.argv[1]))
for number, segment in enumerate(result["segments"]):
    who = f'{segment["speaker"]}: ' if segment.get("speaker") else ""
    print(f'S{number} [{segment["start"]:.1f}-{segment["end"]:.1f}] {who}{segment["text"]}')
```

El agente te devuelve únicamente los números de los tramos:

keep.json

```json
{"keep": [0, 2, 4]}
```

Antes de cortar el vídeo, pídele que te haga una lista de lo que va a quitar y por qué. Volver a generar un corte cuesta poco, pero se tarda mucho menos en leer una lista que en revisar todo el vídeo resultante.

## Paso 3: corta con ffmpeg usando los tiempos de las palabras

El script toma los números de tramo y busca en qué instante empieza la primera palabra y termina la última de cada uno. Luego añade unas centésimas de segundo de margen, junta los tramos que van seguidos y recodifica el vídeo de una sola vez para que el corte sea exacto al fotograma. De paso, recalcula los tiempos de cada palabra según cómo queda el vídeo montado, para que los subtítulos cuadren.

cut.py

```python
# cut.py — ranges from segment numbers, one ffmpeg pass, word times for the new timeline
import subprocess

PAD = 0.08  # seconds of room kept around every range


def ranges_from_ids(segments, keep_ids, pad=PAD):
    """Turn the segment numbers the agent chose into [start, end] ranges in seconds."""
    ranges = []
    for i in sorted(set(keep_ids)):
        segment = segments[i]
        words = segment.get("words") or []
        start = words[0]["start"] if words else segment["start"]
        end = words[-1]["end"] if words else segment["end"]
        start, end = max(0.0, start - pad), end + pad
        if ranges and start <= ranges[-1][1]:
            ranges[-1][1] = max(ranges[-1][1], end)
        else:
            ranges.append([start, end])
    return ranges


def cut(video, ranges, out):
    """Re-encode the kept ranges into one file (frame accurate)."""
    parts = []
    for i, (start, end) in enumerate(ranges):
        parts.append(f"[0:v]trim=start={start:.3f}:end={end:.3f},setpts=PTS-STARTPTS[v{i}]")
        parts.append(f"[0:a]atrim=start={start:.3f}:end={end:.3f},asetpts=PTS-STARTPTS[a{i}]")
    joined = "".join(f"[v{i}][a{i}]" for i in range(len(ranges)))
    parts.append(f"{joined}concat=n={len(ranges)}:v=1:a=1[v][a]")
    subprocess.run(["ffmpeg", "-y", "-hide_banner", "-loglevel", "error", "-i", video,
                    "-filter_complex", ";".join(parts), "-map", "[v]", "-map", "[a]", out], check=True)


def remap(words, ranges):
    """Move word times onto the edited timeline, so subtitles match the cut video."""
    moved, offset = [], 0.0
    for start, end in ranges:
        for word in words:
            if word["start"] >= start and word["end"] <= end:
                moved.append({**word, "start": word["start"] - start + offset,
                              "end": word["end"] - start + offset})
        offset += end - start
    return moved
```

edit.py

```python
# edit.py — the whole pipeline: transcript in, edited video and subtitles out
import json
from kolwrite import upload, transcribe
from cut import ranges_from_ids, cut, remap
from srt_tools import cues_from_words, write_srt

result = transcribe(upload("talk.mp3"), output_format="json", word_timestamps=True)
with open("talk.json", "w", encoding="utf-8") as out:
    json.dump(result, out, ensure_ascii=False)
# ... the agent reads talk.json (python view.py talk.json) and writes keep.json ...

keep = json.load(open("keep.json"))["keep"]
ranges = ranges_from_ids(result["segments"], keep)
cut("talk.mp4", ranges, "edited.mp4")

words = [w for segment in result["segments"] for w in segment.get("words", [])]
write_srt(cues_from_words(remap(words, ranges)), "edited.srt")
```

Cortar sin recodificar (`-c copy`) tarda menos, pero como solo puede cortar en fotogramas clave, el corte se te puede ir varios segundos. Si necesitas que el corte sea exacto, recodifica.

## Paso 4: subtítulos para el vídeo editado

El propio script `edit.py` ya genera el archivo `edited.srt` con los tiempos ajustados al nuevo montaje. En la [guía de SRT](https://console.kolwrite.com/es/guides/srt-subtitles-api) explicamos cómo se montan las líneas.

srt_tools.py

```python
# srt_tools.py — neat subtitle cues from word timings
def srt_time(seconds):
    ms = round(seconds * 1000)
    h, ms = divmod(ms, 3_600_000)
    m, ms = divmod(ms, 60_000)
    s, ms = divmod(ms, 1000)
    return f"{h:02}:{m:02}:{s:02},{ms:03}"


def cues_from_words(words, max_chars=42, max_seconds=6.0, max_gap=0.8):
    """Group timed words into subtitle cues: (start, end, text)."""
    cues, line = [], []
    for word in words:
        text = word["word"].strip()
        if not text:
            continue
        if line:
            length = sum(len(w["word"]) + 1 for w in line) + len(text)
            if (length > max_chars
                    or word["end"] - line[0]["start"] > max_seconds
                    or word["start"] - line[-1]["end"] > max_gap):
                cues.append(line)
                line = []
        line.append({"start": word["start"], "end": word["end"], "word": text})
    if line:
        cues.append(line)
    return [(c[0]["start"], c[-1]["end"], " ".join(w["word"] for w in c)) for c in cues]


def cues_from_result(result):
    """Cues for a whole JSON result; a segment without word times becomes one cue."""
    cues = []
    for segment in result["segments"]:
        if segment.get("words"):
            cues += cues_from_words(segment["words"])
        elif segment["text"].strip():
            cues.append((segment["start"], segment["end"], segment["text"].strip()))
    return cues


def write_srt(cues, path):
    with open(path, "w", encoding="utf-8") as out:
        for number, (start, end, text) in enumerate(cues, 1):
            out.write(f"{number}\n{srt_time(start)} --> {srt_time(end)}\n{text}\n\n")
```

Puedes quemar los subtítulos en el vídeo o añadirlos como una pista aparte que se pueda activar o desactivar en el reproductor:

```bash
ffmpeg -i edited.mp4 -vf "subtitles=edited.srt" -c:a copy burned.mp4
```

```bash
ffmpeg -i edited.mp4 -i edited.srt -c copy -c:s mov_text -metadata:s:s:0 language=eng soft.mp4
```

## Otras cosas que puedes hacer con los tiempos por palabra

- Acortar silencios: quédate con las partes habladas y recorta las pausas que pasen de cierta duración (tienes los detalles en la [guía de marcas de tiempo por palabra](https://console.kolwrite.com/es/guides/word-timestamps-api)).
- Extraer un clip: localiza una frase concreta entre las palabras y recorta ese trozo.
- Limpiar muletillas: haz que el agente descarte los tramos que solo tienen relleno, o búscalas directamente palabra por palabra.
- Crear capítulos y momentos destacados: el agente selecciona los tramos y el script saca las marcas de tiempo (mira la [guía de pódcasts y YouTube](https://console.kolwrite.com/es/guides/podcast-youtube-captions)).
- Aislar o quitar a un hablante: activa `include_diarization` y filtra los tramos según quién hable.

## Cuánto cuesta

| Trabajo | Modelo | Coste |
| --- | --- | --- |
| Clip de 10 minutos, transcrito una sola vez | `oracle` | 0,24 US$ |
| Una hora de vídeo con audio limpio | `base` | 0,48 US$ |
| Una hora de vídeo en calidad de producción | `oracle` | 1,44 US$ |
| Una hora con audio complicado | `oracle_max` | 3,60 US$ |

Cobramos por segundo y sin mínimo. Si un trozo se entiende mal y quieres pasarlo otra vez con un modelo superior, recorta antes ese fragmento de audio y solo pagarás por esos segundos. Puedes ver las tarifas en [/llms/pricing.md](https://console.kolwrite.com/llms/pricing.md).

## Límites a tener en cuenta

- Las marcas de tiempo sirven de sobra para cortar entre una palabra y otra. Pueden bailar un poco justo donde empieza o acaba el sonido, pero el margen que añade `cut.py` lo compensa. De todos modos, escucha siempre cómo quedan los cortes antes de publicar.
- Ninguna transcripción automática es perfecta. Repasa bien los nombres propios y los números antes de publicar nada. KolWrite no ofrece porcentajes de precisión por idioma para esta API.
- Guarda el vídeo original. El script lo usa como base para recodificar los cortes, y lo necesitarás si más adelante decides montar el vídeo de otra manera.
- Si pasas demasiados cortes de golpe, el filtro de ffmpeg se vuelve enorme. Cuando pases de unos cuantos cientos de tramos, es mejor cortar por tandas.

## Preguntas y respuestas

### ¿Puede Claude editar un vídeo?

Claude puede editar un vídeo si tiene acceso a ejecutar comandos. Primero llama a la API de KolWrite para sacar la transcripción con las marcas de tiempo de cada palabra, luego elige con qué frases quedarse y, por último, lanza ffmpeg para hacer los cortes. Esto lo pueden hacer Claude Code, Codex CLI y los agentes de Cursor; una ventana de chat simple solo te puede escribir los scripts.

### ¿Cómo corto un vídeo a partir de su transcripción?

Primero transcribe con marcas de tiempo por palabra y decide qué tramos quieres dejar. Luego toma el inicio de la primera palabra y el final de la última en cada tramo, y usa los filtros trim y concat de ffmpeg para cortar esos intervalos, tal como hace `cut.py`.

### ¿Necesito algún plugin o SDK?

No. La API es HTTPS y JSON; el agente la llama con curl o Python. En el momento de escribir esto no hay un paquete SDK ni un servidor MCP publicados.

### ¿Funciona en hebreo, árabe u otros idiomas?

Para transcribir, sí: la API trabaja con 100 idiomas, ya sea detectándolos sola o pasándole el parámetro `language`. Los tiempos por palabra salen de los modelos que explicamos en la [guía de marcas de tiempo por palabra](https://console.kolwrite.com/es/guides/word-timestamps-api). Haz antes una prueba con un trozo de tus grabaciones y echa un vistazo a la lista de [idiomas](https://console.kolwrite.com/es/languages/).

### ¿Cómo evito que el agente se invente las marcas de tiempo?

Nunca le pidas que te dé marcas de tiempo. Pásale los tramos numerados para que te responda solo con números, y deja que tu propio código calcule los segundos exactos a partir de los tiempos de cada palabra.

## Páginas relacionadas

- [API de subtítulos SRT](https://console.kolwrite.com/es/guides/srt-subtitles-api)
- [API de marcas de tiempo por palabra](https://console.kolwrite.com/es/guides/word-timestamps-api)
- [Herramienta de transcripción para agentes de IA](https://console.kolwrite.com/es/guides/transcription-tool-for-ai-agents)
- [Agentes de IA y vibe coding](https://console.kolwrite.com/es/use-cases/ai-agents)
- [Medios, pódcasts y subtítulos](https://console.kolwrite.com/es/use-cases/media)
- [Documentación de la API](https://console.kolwrite.com/es/public_api_docs)

---
Obtener una clave de API: https://console.kolwrite.com/auth?lang=es · Documentación de la API: https://console.kolwrite.com/es/public_api_docs · llms.txt: https://console.kolwrite.com/llms.txt
