Skip to content

jonny-jhnson/CodexArsenal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CodexArsenal

CodexArsenal is a PowerShell research module for communicating directly with OpenAI's backend APIs.

These APIs are not guaranteed to work as OpenAI could change them over time.

Requirements

  • Windows PowerShell 5.1 or later
  • A ChatGPT account with Codex access

Install

git clone https://github.com/jonny-jhnson/CodexArsenal.git
Import-Module .\CodexArsenal.psd1 -Force

Run Get-Help <cmdlet> -Full for parameters and examples.

Obtaining an Access Token

The easiest way to obtain an access token is locally by looking at .codex\auth.json or you can run Get-CodexTokens if you have a refresh token:

$tokens     = Get-CodexTokens -RefreshToken $refreshToken
$accessToken = $tokens.AccessToken
$accountId   = '<your-account-id>'

If you don't have .codex\auth.json I built Invoke-CodexLogin:

Normal access token (openid profile email offline_access api.connectors.read api.connectors.invoke):

$login = Invoke-CodexLogin
$accessToken = $login.AccessToken
$accountId = $login.AccountId

Remote control enrollment scope (codex.remote_control.enroll) access token:

$stepUp = Invoke-CodexLogin `
    -RemoteControlEnrollment `
    -AccountId $accountId

Discover and invoke MCP tools

List all tools available through the WHAM apps MCP surface, then call one.

Without an explicit MCP session

Get-CodexTool and Invoke-CodexTool create a new MCP session automatically when -SessionId is omitted.

# List available tools
Get-CodexTool -AccessToken $accessToken -AccountId $accountId |
    Select-Object name, description

# Call a tool
Invoke-CodexTool -AccessToken $accessToken -AccountId $accountId `
    -Name gmail_send_email -Arguments @{
        to = 'someone@gmail.com'; subject = 'Hi'; body = 'From Codex'
    }

Reuse a session with Connect-CodexMcp

Create one session and pass its ID to each command when making multiple MCP requests:

$session = Connect-CodexMcp `
    -AccessToken $accessToken `
    -AccountId $accountId

Get-CodexTool `
    -AccessToken $accessToken `
    -AccountId $accountId `
    -SessionId $session |
    Select-Object name, description

Invoke-CodexTool `
    -AccessToken $accessToken `
    -AccountId $accountId `
    -SessionId $session `
    -Name gmail_send_email `
    -Arguments @{
        to = 'someone@gmail.com'
        subject = 'Hi'
        body = 'From Codex'
    }

Invoke-CodexMcp is the low-level JSON-RPC transport underneath Get-CodexTool and Invoke-CodexTool. Use it directly if you need to call arbitrary MCP methods.

Rogue Server Communication

The rogue server scenario is broken down into two pieces - server and controller enrollment. The server registers an environment and listens for requests. The controller enrolls its own identity, claims the server's pairing code, and sends commands through OpenAI's remote-control relay. Both sides make outbound connections and do not need direct network access to each other.

Server

$reg = Register-CodexRemoteServer `
    -AccessToken $accessToken `
    -AccountId $accountId `
    -Name 'RogueVM'

$pair = Start-CodexRemotePairing -ServerEnrollment $reg
$pair | Format-List ManualPairingCode, EnvironmentId, ExpiresAt

$conn = Connect-CodexRemoteServer `
    -RemoteControlToken $reg.RemoteControlToken `
    -ServerId $reg.ServerId `
    -InstallationId $reg.InstallationId `
    -Name $reg.Name

Start-CodexRogueServer -Connection $conn -DurationSeconds 300 -Verbose

Send the short-lived ManualPairingCode to the controller over a separate initial transport.

Controller

The controller requires a normal login and a separate remote-control enrollment login. Both must use the same ChatGPT user and workspace.

$login = Invoke-CodexLogin
$accessToken = $login.AccessToken
$accountId = $login.AccountId

$stepUp = Invoke-CodexLogin `
    -RemoteControlEnrollment `
    -AccountId $accountId

$keyPath = Join-Path $env:USERPROFILE '.codex-arsenal\keys\rogue-controller-key.json'

$client = Register-CodexRemoteClient `
    -AccessToken $accessToken `
    -AccountId $accountId `
    -StepUpToken $stepUp.AccessToken `
    -KeyPath $keyPath

$grant = Complete-CodexRemotePairing `
    -AccessToken $accessToken `
    -AccountId $accountId `
    -ClientEnrollment $client `
    -ManualPairingCode '<code from server>'

$ctl = Connect-CodexRemoteController `
    -AccessToken $accessToken `
    -AccountId $accountId `
    -EnvironmentId $grant.Response.environment_id `
    -ClientEnrollment $client

The controller key file contains exportable private-key material. Treat it like a credential and remove it when done using Remove-Item $keyPath.

If the controller was previously enrolled but its remote-control token has expired, refresh it using the existing client enrollment and device key. This avoids repeating the step-up enrollment:

$client = Update-CodexRemoteClient `
    -ClientEnrollment $client `
    -AccessToken $accessToken `
    -AccountId $accountId

Reconnect with Connect-CodexRemoteController after refreshing the client token.

Send commands:

# Current identity on the server
(Send-CodexRemoteCommand `
    -Connection $ctl `
    -Method 'WhoAmI' `
    -TimeoutSeconds 10).Reply.result.output

# Server and environment information
(Send-CodexRemoteCommand `
    -Connection $ctl `
    -Method 'GetInfo').Reply.result

# Execute a command
(Send-CodexRemoteCommand `
    -Connection $ctl `
    -Method 'Exec' `
    -Params @{ command = 'hostname' }).Reply.result

# Download a small file from the server
$download = (Send-CodexRemoteCommand `
    -Connection $ctl `
    -Method 'DownloadFile' `
    -Params @{ path = 'C:\server\file.txt' }).Reply.result

[System.IO.File]::WriteAllBytes(
    'C:\client\file.txt',
    [Convert]::FromBase64String($download.contentBase64)
)

# Upload a small file to the server
$contentBase64 = [Convert]::ToBase64String(
    [System.IO.File]::ReadAllBytes('C:\client\file.txt')
)

(Send-CodexRemoteCommand `
    -Connection $ctl `
    -Method 'UploadFile' `
    -Params @{
        path = 'C:\server\file.txt'
        contentBase64 = $contentBase64
    }).Reply.result

File transfer (upload and download) is single-frame and intended for files around 100 KB or less.

Refresh an expired server token

$login = Invoke-CodexLogin

$reg = Update-CodexRemoteServer `
    -ServerEnrollment $reg `
    -AccessToken $login.AccessToken `
    -AccountId $login.AccountId

This refreshes the server token without replacing the existing server or environment. The server's ServerId and InstallationId must still be available.

Remove a remote device

Remove-CodexRemoteDevice `
    -AccessToken $login.AccessToken `
    -AccountId $login.AccountId `
    -EnvironmentId $reg.EnvironmentId

Use -WhatIf to preview the removal without deleting the enrollment.

Author

Jonathan Johnson (@JonnyJohnson_)

About

A PowerShell research module for communicating directly with OpenAI's backend APIs.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages