🪝 VS Code Agent Hooks: Give Copilot Context Before the First Message

🪝 VS Code Agent Hooks: Give Copilot Context Before the First Message

A veces requerimos que la IA y el agente tengan un contexto diferente dependiendo de la situación en la que nos encontramos: el tipo de proyecto, la tecnología que estamos usando, el nivel del equipo con el que trabajamos. No es lo mismo arrancar una sesión en un proyecto de cliente que en uno personal, y el agente no tiene forma de saberlo si no se lo dices cada vez, en cada sesión.

¿Sabías que puedes automatizar eso con un script propio? Los Agent Hooks te permiten ejecutar código en puntos específicos del ciclo de vida del agente de forma automática, antes de que el usuario escriba cualquier cosa.

VS Code carga automáticamente todos los archivos .json que estén en .github/hooks/. No se necesita ninguna configuración adicional.

.github/
hooks/
custom-hooks.json ← define qué scripts ejecutar y cuándo
session-start/
log-session.ps1 ← executor SessionStart: hace el onboarding y guarda respuestas
reinject-profile.ps1 ← executor PreCompact: re-inyecta contexto antes de la compactación
questions/
questions.md ← las 3 preguntas con opciones A/B/C que el agente hace al inicio
profiles/
junior.md ← comportamiento del agente para devs junior (tono didáctico, explica más)
mid.md ← comportamiento para devs mid (equilibrio entre detalle y velocidad)
senior.md ← comportamiento para devs senior (directo, sin explicaciones básicas)
results/
session-answers.jsonl ← respuestas del onboarding por sesión (stack, nivel, proyecto)
session-log.jsonl ← log ligero: qué sesión corrió y cuándo
trace-log.jsonl ← log completo: JSON de entrada y salida de cada ejecución

¿Cómo conseguimos que funcione?: Crea .github/hooks/custom-hooks.json

  • type: Define que el hook ejecuta un comando externo («command» es el único tipo disponible por ahora).
  • windows: El comando que se ejecuta en Windows, en este caso, un script de PowerShell.
  • command: Fallback si no hay windows, VS Code usa este.
  • cwd: Directorio de trabajo desde donde corre el script, relativo a la raíz del repositorio.
  • env: Variables de entorno adicionales que el script puede leer (por ejemplo, $env:HOOK_AUTHOR).
  • timeout: Segundos que VS Code espera la respuesta antes de continuar sin ella.
{
"hooks": {
"SessionStart": [
{
"type": "command",
"windows": "powershell -ExecutionPolicy Bypass -File log-session.ps1",
"command": "echo '{\"continue\":true}'",
"cwd": ".github/hooks/session-start",
"env": {
"HOOK_AUTHOR": "GDRGDev"
},
"timeout": 20
}
],
"PreCompact": [
{
"type": "command",
"windows": "powershell -ExecutionPolicy Bypass -File reinject-profile.ps1",
"command": "echo '{\"continue\":true}'",
"cwd": ".github/hooks/session-start",
"timeout": 10
}
]
}
}

El hook «SessionStart» dispara una sola vez cuando comienza una sesión nueva. El script «log-session.ps1» le indica al agente que haga 3 preguntas al usuario (una por una).

Así se ve una entrada en trace-log.jsonl, que es el log completo con el input que recibe el hook al dispararse:

{
"timestamp": "2026-05-03T15:24:34.767Z",
"session_id": "084b9fc7-121a-469c-b966-e2a11f35f5d2",
"author": "GDRGDev",
"input": {
"timestamp": "2026-05-03T13:24:34.206Z",
"hook_event_name": "SessionStart",
"session_id": "084b9fc7-121a-469c-b966-e2a11f35f5d2",
"transcript_path": "c:\\Users\\..\\AppData\\Roaming\\Code\\User\\workspaceStorage\\77f53d206a128cd28ad4272b080a0f7a\\GitHub.copilot-chat\\transcripts\\084b9fc7-121a-469c-b966-e2a11f35f5d2.jsonl",
"source": "new",
"model": "claude-sonnet-4.6",
"cwd": "c:\\...\\zPersonal\\GDRGDev_1\\.github\\hooks\\session-start"
},
"output": {
"continue": true,
"systemMessage": "[GDRGDev] SessionStart hook fired at 15:24:34",
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext":
"IMPORTANT: New session started. No context exists yet." `
"Your first response must be Q1 only. Do not greet, do not explain, do not answer anything else." `
"Ask Q1, wait for the answer, then Q2, then Q3." `
"Always ask and respond in English." `
"" `
"Q1: What are you working on today?" `
" A) AL extension" `
" B) VS Code extension" `
" C) Other" `
"" `
.....
.....

El «additionalContext» ya es suficiente para que la IA conozca el contexto de la sesión, dentro de ese mismo texto le indicamos al agente que serialice las respuestas en un archivo JSONL. Sin ese paso, «PreCompact» no tendría nada que leer si la conversación se compacta. Una vez guardadas, el agente activa el perfil correspondiente con sus propias instrucciones de comportamiento.

El archivo session-log.jsonl guarda solo timestamp, session_id y author, una línea por sesión, sin el payload completo. Útil para auditar sin abrir el trace.

Y en session-answers.jsonl queda guardado el resultado del onboarding, es lo que PreCompact va a leer para re-inyectar el contexto si la sesión se compacta:

{
"session_id": "084b9fc7-121a-469c-b966-e2a11f35f5d2",
"timestamp": "2026-05-03T00:00:00Z",
"answers": {
"stack": "A - AL extension",
"level": "C - Senior",
"project": "A - Personal"
}
}

Cuando una conversación es muy larga, VS Code compacta el contexto automáticamente, ¿cuál sería el problema? el agente puede perder las respuestas del onboarding y empezar a comportarse como si no supiera nada. El Hook «PreCompact» se dispara justo antes de esa compactación. Por lo que, es la oportunidad de re-inyectar contexto antes de que se pierda.

El script «reinject-profile.ps1» lee las respuestas de la sesión actual desde el JSONL y carga el perfil activo, además de devolver e inyectar el contexto con las respuestas y el perfil completo.

Espero que esta información te ayude.


🪝 VS Code Agent Hooks: Give Copilot Context Before the First Message

Sometimes we need the AI ​​and the human agent to have different context depending on the situation: the type of project, the technology we’re using, the level of the team we’re working with. Starting a session in a client project is not the same as starting a personal one, and the agent has no way of knowing this unless you tell it every time, in every session.

Did you know you can automate that with your own script? Agent Hooks allow you to automatically run code at specific points in the agent lifecycle, before the user types anything.

VS Code automatically loads all .json files located in .github/hooks/. ​​No additional configuration is required.

.github/
hooks/
custom-hooks.json ← defines which scripts to run and when
session-start/
log-session.ps1 ← SessionStart executor: runs onboarding and saves answers
reinject-profile.ps1 ← PreCompact executor: re-injects context before compaction
questions/
questions.md ← the 3 questions with A/B/C options the agent asks at session start
profiles/
junior.md ← agent behavior for junior devs (didactic tone, more explanations)
mid.md ← behavior for mid-level devs (balance between detail and speed)
senior.md ← behavior for senior devs (direct, no basic explanations)
results/
session-answers.jsonl ← onboarding answers per session (stack, level, project)
session-log.jsonl ← lightweight log: which session ran and when
trace-log.jsonl ← full trace log: input and output JSON for each execution

How do we make it work?: Create .github/hooks/custom-hooks.json

  • type: Defines that the hook runs an external command («command» is the only type available right now).
  • windows: The command executed on Windows, in this case, a PowerShell script.
  • command: Fallback when windows is not defined; VS Code uses this on Linux/macOS.
  • cwd: Working directory from which the script runs, relative to the repository root.
  • env: Additional environment variables the script can read (e.g., $env:HOOK_AUTHOR).
  • timeout: Seconds VS Code waits for a response before continuing without it.
{
"hooks": {
"SessionStart": [
{
"type": "command",
"windows": "powershell -ExecutionPolicy Bypass -File log-session.ps1",
"command": "echo '{\"continue\":true}'",
"cwd": ".github/hooks/session-start",
"env": {
"HOOK_AUTHOR": "GDRGDev"
},
"timeout": 20
}
],
"PreCompact": [
{
"type": "command",
"windows": "powershell -ExecutionPolicy Bypass -File reinject-profile.ps1",
"command": "echo '{\"continue\":true}'",
"cwd": ".github/hooks/session-start",
"timeout": 10
}
]
}
}

The «SessionStart» hook fires only once when a new session begins. The «log-session.ps1» script instructs the agent to ask the user three questions (one at a time).

This is what an entry in trace-log.jsonl looks like, which is the complete log with the input received by the hook when it fires:

{
"timestamp": "2026-05-03T15:24:34.767Z",
"session_id": "084b9fc7-121a-469c-b966-e2a11f35f5d2",
"author": "GDRGDev",
"input": {
"timestamp": "2026-05-03T13:24:34.206Z",
"hook_event_name": "SessionStart",
"session_id": "084b9fc7-121a-469c-b966-e2a11f35f5d2",
"transcript_path": "c:\\Users\\..\\AppData\\Roaming\\Code\\User\\workspaceStorage\\77f53d206a128cd28ad4272b080a0f7a\\GitHub.copilot-chat\\transcripts\\084b9fc7-121a-469c-b966-e2a11f35f5d2.jsonl",
"source": "new",
"model": "claude-sonnet-4.6",
"cwd": "c:\\...\\zPersonal\\GDRGDev_1\\.github\\hooks\\session-start"
},
"output": {
"continue": true,
"systemMessage": "[GDRGDev] SessionStart hook fired at 15:24:34",
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext":
"IMPORTANT: New session started. No context exists yet." `
"Your first response must be Q1 only. Do not greet, do not explain, do not answer anything else." `
"Ask Q1, wait for the answer, then Q2, then Q3." `
"Always ask and respond in English." `
"" `
"Q1: What are you working on today?" `
" A) AL extension" `
" B) VS Code extension" `
" C) Other" `
"" `
.....
.....

The «additionalContext» is already sufficient for the AI ​​to understand the session context. Within that same text, we instruct the agent to serialize the responses into a JSONL file. Without this step, «PreCompact» would have nothing to read if the conversation is compacted. Once saved, the agent activates the corresponding profile with its own behavioral instructions.

The session-log.jsonl file saves only the timestamp, session_id, and author, one line per session, without the full payload. Useful for auditing without opening the trace.

The onboarding result is saved in session-answers.json; this is what PreCompact will read to reinject the context if the session is compacted.

{
"session_id": "084b9fc7-121a-469c-b966-e2a11f35f5d2",
"timestamp": "2026-05-03T00:00:00Z",
"answers": {
"stack": "A - AL extension",
"level": "C - Senior",
"project": "A - Personal"
}
}

When a conversation is very long, VS Code automatically compacts the context. What’s the problem? The agent might miss the onboarding responses and start behaving as if it knows nothing. The «PreCompact» hook fires just before this compaction occurs. Therefore, it’s an opportunity to reinject context before it’s lost.

The script «reinject-profile.ps1» reads the responses from the current session from the JSONL and loads the active profile, in addition to returning and injecting the context with the responses and the complete profile.

I hope this information helps you.


Más información / More information:

Deja un comentario