diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,9 @@
 # Revision history for pms-infra-agent-server
 
+## 0.0.2.0 -- 2026-07-05
+
+* Modify readme.md.
+
 ## 0.0.1.0 -- 2026-06-02
 
 * First version.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,311 @@
+# pms-infra-agent-server
+
+----
+## ⚠️ Caution
+
+**Do not grant unrestricted control to AI.**
+
+Unsupervised use or misuse may lead to unintended consequences.
+All AI systems must remain strictly under human oversight and control.
+Use responsibly, with full awareness and at your own risk.
+
+----
+## 📘 Overview
+
+**`pms-infra-agent-server`** is a Haskell infrastructure library that enables AI agents to act as a **TCP server**, accepting inbound connections from external clients and exchanging arbitrary data at the byte level.
+
+Unlike client-oriented socket libraries, this library exposes server-side listen, accept, and I/O operations as MCP tools. The agent retains full control over protocol handling — whether Telnet, HTTP, custom binary frames, or AI-to-AI communication protocols.
+
+The library is a core component of the [`pty-mcp-server`](https://github.com/phoityne/pty-mcp-server) ecosystem and implements the `agent-server-*` family of MCP tools.
+
+---
+
+## 🔧 Provided MCP Tools
+
+### `agent-server-listen`
+Binds to the specified host and port, starts listening for incoming TCP connections, and launches a background accept thread. Returns immediately after the listener is ready.
+Only one listener can be active at a time.
+
+- `host` — Bind address (e.g. `0.0.0.0` for all interfaces, `127.0.0.1` for loopback)
+- `port` — Port number to listen on (e.g. `19999`)
+
+### `agent-server-close`
+Closes the active accepted connection (if any). If no connection is active, also closes the listener.
+Call twice to close both the accepted connection and the listener independently.
+
+### `agent-server-status`
+Returns the current server status as a JSON object.
+
+```json
+{ "isListening": true, "isConnected": false }
+```
+
+- `isListening` — Whether the listener socket is active
+- `isConnected` — Whether an accepted connection is currently open
+
+### `agent-server-events`
+Dequeues and returns all server-side events accumulated since the last call.
+Returns an empty array if no events are pending.
+
+Event types:
+- `ClientConnected` — A client has been accepted
+- `BytesReceived` — Bytes received from the client (hex-encoded)
+- `ClientDisconnected` — The client has closed the connection
+
+```json
+[
+  { "tag": "ClientConnected", "handleName": "default" },
+  { "tag": "BytesReceived", "handleName": "default", "bytes": "68656C6C6F0D0A" },
+  { "tag": "ClientDisconnected", "handleName": "default" }
+]
+```
+
+### `agent-server-read`
+Reads data from the active accepted connection and returns it as a **UTF-8 string**.
+Returns an empty string if no data is available before timeout.
+
+> ⚠️ If the received data contains non-UTF-8 bytes or binary protocol frames, use `agent-server-read-byte` instead.
+
+### `agent-server-read-byte`
+Reads data from the active accepted connection and returns it as an **uppercase hex string** (e.g. `FF0A1B41`).
+Use this for binary protocols or when precise byte-level inspection is required.
+
+### `agent-server-write`
+Writes the specified **UTF-8 string** to the active accepted connection.
+
+- `data` — Text data to write
+
+> ⚠️ `\r\n` in the string is sent as the two literal characters `\` and `r`, not as CRLF bytes.
+> Use `agent-server-write-byte` when correct CRLF (or any exact byte sequence) is required.
+
+### `agent-server-write-byte`
+Decodes the specified **hex string** and writes the resulting bytes to the active accepted connection.
+Use this for binary protocols or when precise byte-level control is required.
+
+- `data` — Hex string to decode and write (e.g. `48656C6C6F0D0A`; uppercase and lowercase are accepted, no spaces or newlines)
+
+---
+
+## 💡 Usage Notes
+
+### Busy rejection
+If a second client attempts to connect while a connection is already active, the server automatically sends `busy\r\n` to the second client and closes it immediately. The existing connection is unaffected.
+
+### CRLF and binary sending
+Always use `agent-server-write-byte` when the protocol requires exact CRLF bytes or binary content.
+Generate hex strings with:
+```bash
+python3 -c "print('HELLO\r\n'.encode().hex())"
+```
+> The hex string passed to `agent-server-write-byte` must not contain spaces or newlines.
+
+### Receiving data
+There is no blocking read tool. Data arrives asynchronously via the internal event queue.
+Poll `agent-server-events` to retrieve `BytesReceived` events and decode the hex bytes.
+
+### Closing sequence
+When initiating a graceful shutdown, send a `BYE\r\n` signal to the client **and wait for the client's `ACK\r\n`** (polled via `agent-server-events`) before calling `agent-server-close`.
+Closing immediately after sending `BYE` may cause the client to miss the message.
+
+```
+Server → Client : BYE\r\n
+Server ← Client : ACK\r\n   ← wait for this via agent-server-events
+Server  agent-server-close
+```
+
+### AI-to-AI communication protocol
+This library ships with two MCP prompt skills for AI-to-AI TCP communication:
+
+| Skill | File | Trigger examples |
+|-------|------|------------------|
+| Server role | `skill_agent_server.md` | "start the server", "listen on port 19999" |
+| Client role | `skill_agent_client.md` | "connect to 172.16.0.43:19999", "connect to the AI server" |
+
+Handshake protocol:
+```
+Server → Client : HELLO? name?\r\n
+Server ← Client : NAME: <name>\r\n
+Server → Client : RULES: MSG:<content>\r\n | REPLY:<content>\r\n | BYE\r\n | HEX:<hex>\r\n
+Server ← Client : ACK\r\n
+--- conversation ---
+Server → Client : BYE\r\n
+Server ← Client : ACK\r\n
+```
+
+---
+
+## 🚀 Usage Examples
+
+### Example 1: Telnet client session
+
+This example shows a full session where a telnet client connects, sends `hello`, and disconnects.
+
+**Step 1 — Start listening**
+```
+[Agent] agent-server-listen host="0.0.0.0" port=19999
+→ "listening."
+```
+
+**Step 2 — Client connects (telnet 172.16.0.43 19999)**
+```
+[Agent] agent-server-events
+→ [{ "tag": "ClientConnected", "handleName": "default" }]
+```
+
+**Step 3 — Client sends "hello" and disconnects (Ctrl+] → quit)**
+```
+[Agent] agent-server-events
+→ [
+    { "tag": "BytesReceived", "handleName": "default", "bytes": "68656C6C6F0D0A" },
+    { "tag": "ClientDisconnected", "handleName": "default" }
+  ]
+```
+`68656C6C6F0D0A` decodes to `hello\r\n`.
+
+**Step 4 — Confirm listener is still active after disconnect**
+```
+[Agent] agent-server-status
+→ { "isListening": true, "isConnected": false }
+```
+
+**Step 5 — Stop listening**
+```
+[Agent] agent-server-close
+→ "listener closed."
+
+[Agent] agent-server-status
+→ { "isListening": false, "isConnected": false }
+```
+
+---
+
+### Example 2: Busy rejection
+
+When a second client connects while a connection is already active, the server automatically rejects it.
+
+```
+[Agent] agent-server-listen host="0.0.0.0" port=19999
+→ "listening."
+
+--- Client A connects: telnet 172.16.0.43 19999 (connection maintained) ---
+
+--- Client B connects: telnet 172.16.0.43 19999 ---
+Client B receives: "busy"
+Client B sees:     "Connection closed by foreign host."
+
+[Agent] agent-server-status
+→ { "isListening": true, "isConnected": true }   ← Client A is still connected
+
+[Agent] agent-server-events
+→ []   ← busy rejection does not produce events
+```
+
+---
+
+### Example 3: HTTP response via curl
+
+This example shows the agent acting as an HTTP server, receiving a `GET` request from `curl` and responding with an HTML document.
+
+**Step 1 — Start listening**
+```
+[Agent] agent-server-listen host="0.0.0.0" port=19999
+→ "listening."
+```
+
+**Step 2 — curl sends an HTTP request**
+```bash
+$ curl http://172.16.0.43:19999/
+```
+
+**Step 3 — Read the HTTP request from the event queue**
+```
+[Agent] agent-server-events
+→ [{
+    "tag": "BytesReceived",
+    "handleName": "default",
+    "bytes": "474554202F20485454502F312E310D0A486F73743A203137322E31362E302E34333A31393939390D0A557365722D4167656E743A206375726C2F382E31322E310D0A4163636570743A202A2F2A0D0A0D0A"
+  }]
+```
+Decoded:
+```
+GET / HTTP/1.1\r\n
+Host: 172.16.0.43:19999\r\n
+User-Agent: curl/8.12.1\r\n
+Accept: */*\r\n
+\r\n
+```
+
+**Step 4 — Send the HTTP response using `agent-server-write-byte`**
+
+Generate the hex for the response:
+```bash
+python3 -c "print((
+  'HTTP/1.1 200 OK\r\n'
+  'Content-Type: text/html; charset=utf-8\r\n'
+  'Content-Length: 46\r\n'
+  'Connection: close\r\n'
+  '\r\n'
+  '<html><body>Hello from AI Agent!</body></html>'
+).encode().hex())"
+```
+
+```
+[Agent] agent-server-write-byte data="<hex string above>"
+[Agent] agent-server-close
+```
+
+**Result on the curl side:**
+```
+$ curl http://172.16.0.43:19999/
+<html><body>Hello from AI Agent!</body></html>
+```
+
+> ⚠️ Always use `agent-server-write-byte` (not `agent-server-write`) for HTTP responses.
+> `agent-server-write` sends `\r\n` as two literal characters, not as CRLF bytes,
+> causing `curl` to report `Recv failure`.
+
+---
+
+
+### Module Structure
+
+```
+PMS.Infra.Agent.Server
+├── CoreModel
+│   └── Type          -- Data type definitions (AppData, command types, event types)
+├── ProjectedContext
+│   └── Core          -- Core domain service logic (recvLoop, sendLoop)
+├── ApplicationBase
+│   ├── Control       -- Tool dispatch and server lifecycle management
+│   └── State
+│       ├── Idle       -- State: no listener active
+│       ├── Listening  -- State: listener active, no connection
+│       └── Connected  -- State: connection accepted
+└── Interface
+    └── Network       -- TCP socket operations (listen, accept, send, recv)
+```
+
+### Key Design Points
+
+- **State machine**: Server lifecycle is modelled as three explicit states — `Idle`, `Listening`, and `Connected`. Each state handles only the events valid for that state.
+- **Single active connection**: Only one accepted connection can be active at a time. A second incoming connection receives `busy\r\n` and is rejected.
+- **Background accept thread**: `agent-server-listen` returns immediately; a background thread waits for `accept` and pushes a `ClientConnected` event into the queue.
+- **Event queue**: All inbound data and connection lifecycle events are pushed to an STM `TQueue`. The agent polls via `agent-server-events`.
+- **Socket-based I/O**: All read/write operations use `Network.Socket` directly (no `Handle` abstraction), ensuring predictable close semantics.
+
+---
+
+## 📦 Dependencies
+
+- [`pms-domain-model`](https://github.com/phoityne/pms-domain-model)
+- `network`
+- `stm`
+- `async`
+
+---
+
+## 📜 Credits & License
+
+- **Execution & Process Lead:** Claude Sonnet 4.6
+- **Direction & Policy:** phoityne
+- **License:** Apache-2.0 — see [LICENSE](./LICENSE)
diff --git a/pms-infra-agent-server.cabal b/pms-infra-agent-server.cabal
--- a/pms-infra-agent-server.cabal
+++ b/pms-infra-agent-server.cabal
@@ -1,19 +1,34 @@
 cabal-version:      2.4
 name:               pms-infra-agent-server
-version:            0.0.1.0
-synopsis:           TCP server listener library for pty-mcp-server agent tools
-description:        Provides agent-server-* MCP tools: bind/listen/accept thread,
-                    event queue, read/write over accepted connections.
-homepage:           https://hackage.haskell.org/package/pty-mcp-server
-bug-reports:        https://github.com/phoityne/pty-mcp-server/issues
+
+-- The package version.
+-- See the Haskell package versioning policy (PVP) for standards
+-- guiding when and how versions should be incremented.
+-- https://pvp.haskell.org
+-- PVP summary:     +-+------- breaking API changes
+--                  | | +----- non-breaking API additions
+--                  | | | +--- code changes with no API change
+version:            0.0.2.0
+
+-- A short (one-line) description of the package.
+synopsis:           pms-infra-agent-server
+
+-- A longer description of the package.
+description:        README.md
+
 license:            Apache-2.0
 license-file:       LICENSE
 author:             phoityne.hs@gmail.com
 maintainer:         phoityne.hs@gmail.com
-copyright:          2024 phoityne.hs@gmail.com
-category:           System
+copyright:          2025-2026 phoityne.hs@gmail.com
+category:           AI
 build-type:         Simple
-extra-doc-files:    CHANGELOG.md
+homepage:           https://github.com/phoityne/pms-infra-agent-server
+bug-reports:        https://github.com/phoityne/pms-infra-agent-server/issues
+
+-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.
+extra-doc-files:    README.md,
+                    CHANGELOG.md
 
 common warnings
 
