diff --git a/include/toksvc/toksvc.h b/include/toksvc/toksvc.h
index 982446a..0725ed7 100644
--- a/include/toksvc/toksvc.h
+++ b/include/toksvc/toksvc.h
@@ -39,6 +39,9 @@ extern "C" {
 #define TOKS_DRIVER_VERSION		0x0010
 #define TOKS_DRIVER_DRY_RUN		0x0020
 
+#define TOKS_DRIVER_DAEMON_ALWAYS	0x0040
+#define TOKS_DRIVER_DAEMON_NEVER	0x0080
+
 #define TOKS_DRIVER_ANNOTATE_ALWAYS	0x1000
 #define TOKS_DRIVER_ANNOTATE_NEVER	0x2000
 #define TOKS_DRIVER_ANNOTATE_FULL	0x4000
diff --git a/project/common.mk b/project/common.mk
index e41c495..adb5eb2 100644
--- a/project/common.mk
+++ b/project/common.mk
@@ -1,6 +1,10 @@
 API_SRCS = \
 
 INTERNAL_SRCS = \
+	src/daemon/toks_daemon_connect.c \
+	src/daemon/toks_daemon_init.c \
+	src/daemon/toks_daemon_loop.c \
+	src/daemon/toks_daemon_signal.c \
 	src/internal/nolibc/toksvc_compiler.c \
 	src/internal/toksvc_dprintf_impl.c \
 	src/internal/toksvc_memfn_impl.c \
diff --git a/project/headers.mk b/project/headers.mk
index 34ab9b7..9ea381f 100644
--- a/project/headers.mk
+++ b/project/headers.mk
@@ -11,6 +11,7 @@ INTERNAL_HEADERS = \
 	$(SOURCE_DIR)/src/internal/nolibc/stdlib.h \
 	$(SOURCE_DIR)/src/internal/nolibc/string.h \
 	$(SOURCE_DIR)/src/internal/nolibc/unistd.h \
+	$(SOURCE_DIR)/src/internal/toksvc_daemon_impl.h \
 	$(SOURCE_DIR)/src/internal/toksvc_dprintf_impl.h \
 	$(SOURCE_DIR)/src/internal/toksvc_init_impl.h \
 	$(SOURCE_DIR)/src/internal/toksvc_memfn_impl.h \
diff --git a/project/tree.mk b/project/tree.mk
index e593d53..2d04bf6 100644
--- a/project/tree.mk
+++ b/project/tree.mk
@@ -1,4 +1,5 @@
 TREE_DIRS     = bin src lib \
+		src/daemon \
 		src/internal \
 		src/internal/nolibc \
 
diff --git a/src/daemon/toks_daemon_connect.c b/src/daemon/toks_daemon_connect.c
new file mode 100644
index 0000000..66595db
--- /dev/null
+++ b/src/daemon/toks_daemon_connect.c
@@ -0,0 +1,27 @@
+/*********************************************************/
+/*  toksvc: a framework-native token broker service      */
+/*  Copyright (C) 2020  Z. Gilboa                        */
+/*  Released under GPLv2 and GPLv3; see COPYING.TOKSVC.  */
+/*********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/ntapi.h>
+
+#include <toksvc/toksvc.h>
+#include "toksvc_daemon_impl.h"
+#include "toksvc_driver_impl.h"
+
+int32_t __stdcall toks_daemon_connect(nt_tty_port_msg * msg)
+{
+	void * hport = 0;
+
+	msg->ttyinfo.exarg = 0;
+
+	ntapi->zw_accept_connect_port(
+		&hport,
+		msg->header.client_id.process_id,
+		&msg->header,
+		NT_LPC_ACCEPT_CONNECTION,0,0);
+
+	return ntapi->zw_complete_connect_port(hport);
+}
diff --git a/src/daemon/toks_daemon_init.c b/src/daemon/toks_daemon_init.c
new file mode 100644
index 0000000..d11d347
--- /dev/null
+++ b/src/daemon/toks_daemon_init.c
@@ -0,0 +1,128 @@
+/*********************************************************/
+/*  toksvc: a framework-native token broker service      */
+/*  Copyright (C) 2020  Z. Gilboa                        */
+/*  Released under GPLv2 and GPLv3; see COPYING.TOKSVC.  */
+/*********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/ntapi.h>
+#include <ntapi/nt_atomic.h>
+
+#include <toksvc/toksvc.h>
+#include "toksvc_daemon_impl.h"
+#include "toksvc_driver_impl.h"
+
+static const nt_guid toks_daemon_guid = TOKS_PORT_GUID_DAEMON;
+
+static int32_t toks_daemon_init_impl(struct toks_daemon_ctx * dctx, void * htty)
+{
+	int32_t				status;
+	nt_daemon_params		dparams;
+	wchar16_t *			port_name;
+	nt_port_name_keys *		port_name_keys;
+
+	/* daemon attributes */
+	dctx->daemon_attr.type    = NT_PORT_TYPE_DAEMON;
+	dctx->daemon_attr.subtype = NT_PORT_SUBTYPE_DEFAULT;
+
+	/* port guid */
+	ntapi->tt_guid_copy(
+		&dctx->daemon_attr.guid,
+		&toks_daemon_guid);
+
+	/* port keys */
+	if ((status = ntapi->tt_port_generate_keys(&dctx->daemon_attr.keys)))
+		return status;
+
+	/* port name */
+	ntapi->tt_port_name_from_attr(
+		&dctx->daemon_name,
+		&dctx->daemon_attr);
+
+	/* dparams */
+	ntapi->tt_aligned_block_memset(
+		&dparams,0,sizeof(dparams));
+
+	port_name      = (wchar16_t *)&dctx->daemon_name;
+	port_name_keys = (nt_port_name_keys *)&dctx->daemon_name.port_name_keys;
+
+	dparams.port_keys	= &dctx->daemon_keys;
+	dparams.port_name	= port_name;
+	dparams.port_name_keys	= port_name_keys;
+
+	dparams.port_msg_size	= sizeof(nt_tty_port_msg);
+	dparams.flags		= NT_DSR_INIT_DEFAULT;
+
+	dparams.daemon_once_routine	= 0;
+	dparams.daemon_loop_routine	= toks_daemon_loop;
+	dparams.daemon_loop_context	= dctx;
+
+	dparams.pport_daemon		= &dctx->hport_daemon;
+	dparams.pport_internal_client	= &dctx->hport_internal_client;
+
+	dparams.pevent_daemon_ready		= &dctx->hevent_daemon_ready;
+	dparams.pevent_internal_client_ready	= &dctx->hevent_internal_client_ready;
+
+	dparams.stack_size_commit		= 8192;
+	dparams.stack_size_reserve		= 8192;
+
+	if ((status = ntapi->dsr_init(&dparams)))
+		return status;
+
+	return ntapi->tty_request_peer(
+                htty,
+		TOKS_DAEMON_TTYSIGNAL,
+		0,&(nt_guid)TTY_PTS_GUID,
+		&dctx->daemon_attr);
+}
+
+static int32_t toks_daemon_once = 0;
+
+int32_t __stdcall toks_daemon_init(struct toks_daemon_ctx * dctx, uint64_t drvflags)
+{
+	int32_t			status;
+	nt_timeout		timeout;
+	nt_runtime_data *	rtdata;
+
+	/* rtdata */
+	if ((status = ntapi->tt_get_runtime_data(&rtdata,0)))
+		return status;
+
+	/* needed? */
+	if (drvflags & TOKS_DRIVER_DAEMON_NEVER)
+		return 0;
+
+	if (!(drvflags & TOKS_DRIVER_DAEMON_ALWAYS))
+		if (ntapi->tt_guid_compare(&rtdata->srv_guid,&toks_daemon_guid))
+			return 0;
+
+	/* once */
+	switch (at_locked_cas_32(&toks_daemon_once,0,1)) {
+		case 0:
+			if ((status = toks_daemon_init_impl(dctx,rtdata->hsession))) {
+				at_locked_add_32(&toks_daemon_once,2);
+				return status;
+			}
+
+			at_locked_inc_32(&toks_daemon_once);
+			return 0;
+
+		case 1:
+			timeout.quad = -10;
+
+			for (; (at_locked_cas_32(&toks_daemon_once,0,1) == 1); )
+				ntapi->zw_delay_execution(
+					NT_SYNC_ALERTABLE,
+					&timeout);
+
+			return (toks_daemon_once == 2)
+				? 0 : -1;
+
+		case 2:
+			return 0;
+
+		case 3:
+		default:
+			return -1;
+	}
+}
diff --git a/src/daemon/toks_daemon_loop.c b/src/daemon/toks_daemon_loop.c
new file mode 100644
index 0000000..fb151ec
--- /dev/null
+++ b/src/daemon/toks_daemon_loop.c
@@ -0,0 +1,125 @@
+/*********************************************************/
+/*  toksvc: a framework-native token broker service      */
+/*  Copyright (C) 2020  Z. Gilboa                        */
+/*  Released under GPLv2 and GPLv3; see COPYING.TOKSVC.  */
+/*********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/ntapi.h>
+
+#include <toksvc/toksvc.h>
+#include "toksvc_daemon_impl.h"
+#include "toksvc_driver_impl.h"
+
+#define TOKS_VTBL_ELEMENTS   TOKS_DAEMON_OPCODE_CAP - TOKS_DAEMON_OPCODE_BASE
+
+static toks_daemon_routine * toks_daemon_vtbl[TOKS_VTBL_ELEMENTS] = {
+	toks_daemon_connect,
+	0,
+	toks_daemon_signal,
+	0,
+	0,
+	0
+};
+
+int32_t __stdcall toks_daemon_loop(void * ctx)
+{
+	struct toks_daemon_ctx *	dctx;
+	nt_rtdata *			rtdata;
+
+	nt_tty_port_msg			inbuf;
+	nt_tty_port_msg			outbuf;
+
+	nt_tty_port_msg *		request;
+	nt_tty_port_msg *		reply;
+
+	intptr_t			port_id;
+	int32_t				opcode;
+
+	if (ntapi->tt_get_runtime_data(&rtdata,0))
+		return NT_STATUS_INTERNAL_ERROR;
+
+	dctx = (struct toks_daemon_ctx *)ctx;
+
+	/* init */
+	request = &inbuf;
+	ntapi->tt_aligned_block_memset(
+		request,0,sizeof(*request));
+
+	/* get first message */
+	ntapi->zw_reply_wait_receive_port(
+		dctx->hport_daemon,
+		&port_id,
+		0,(nt_port_message *)request);
+
+	/* message loop */
+	do {
+		switch (request->header.msg_type) {
+			case NT_LPC_REQUEST:
+			case NT_LPC_DATAGRAM:
+				opcode = request->ttyinfo.opcode;
+				break;
+
+			case NT_LPC_CONNECTION_REQUEST:
+				opcode = TOKS_DAEMON_CONNECT;
+				break;
+
+			default:
+				opcode = -1;
+				break;
+		}
+
+		/* dispatch */
+		reply = &outbuf;
+
+		ntapi->tt_aligned_block_memcpy(
+			(uintptr_t *)reply,
+			(uintptr_t *)request,
+			sizeof(*reply));
+
+		reply->header.msg_type = NT_LPC_REPLY;
+
+		if ((opcode >= TOKS_DAEMON_OPCODE_BASE) && (opcode < TOKS_DAEMON_OPCODE_CAP)) {
+			reply->ttyinfo.exarg = (void *)request->header.client_id.process_id;
+			opcode -= TOKS_DAEMON_OPCODE_BASE;
+
+			if (toks_daemon_vtbl[opcode])
+				reply->ttyinfo.status = toks_daemon_vtbl[opcode](reply);
+			else
+				reply->ttyinfo.status = NT_STATUS_NOT_IMPLEMENTED;
+		} else {
+			reply->ttyinfo.exarg    = NT_INVALID_HANDLE_VALUE;
+			reply->ttyinfo.status   = NT_STATUS_LPC_INVALID_CONNECTION_USAGE;
+		}
+
+		ntapi->tt_aligned_block_memset(
+			request,0,sizeof(*request));
+
+		reply = reply->ttyinfo.exarg
+			? &outbuf : 0;
+
+		if (!reply)
+			ntapi->zw_reply_wait_receive_port(
+				dctx->hport_daemon,
+				&port_id,
+				0,&request->header);
+		else if (reply->header.client_id.process_id == rtdata->cid_self.process_id)
+			ntapi->zw_reply_wait_receive_port(
+				dctx->hport_daemon,
+				&port_id,
+				&reply->header,
+				&request->header);
+		else {
+			ntapi->zw_reply_port(
+				dctx->hport_daemon,
+				&reply->header);
+
+			ntapi->zw_reply_wait_receive_port(
+				dctx->hport_daemon,
+				&port_id,
+				0,&request->header);
+		}
+	} while (request->header.msg_id);
+
+	return NT_STATUS_INTERNAL_ERROR;
+}
diff --git a/src/daemon/toks_daemon_signal.c b/src/daemon/toks_daemon_signal.c
new file mode 100644
index 0000000..1c7454a
--- /dev/null
+++ b/src/daemon/toks_daemon_signal.c
@@ -0,0 +1,27 @@
+/*********************************************************/
+/*  toksvc: a framework-native token broker service      */
+/*  Copyright (C) 2020  Z. Gilboa                        */
+/*  Released under GPLv2 and GPLv3; see COPYING.TOKSVC.  */
+/*********************************************************/
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/ntapi.h>
+#include <ntapi/nt_termios.h>
+
+#include "toksvc_daemon_impl.h"
+#include "toksvc_driver_impl.h"
+
+int32_t __stdcall toks_daemon_signal(nt_tty_port_msg * msg)
+{
+	/* [not a] ctty signal? */
+	if (msg->ctlinfo.ctxarg[0])
+		return NT_STATUS_SUCCESS;
+
+	/* ctty sigint */
+	if (msg->ctlinfo.ctlcode == TTY_TCSBRK)
+		ntapi->zw_terminate_process(
+			NT_CURRENT_PROCESS_HANDLE,
+			NT_STATUS_WAIT_1);
+
+	return NT_STATUS_NOT_SUPPORTED;
+}
diff --git a/src/internal/toksvc_daemon_impl.h b/src/internal/toksvc_daemon_impl.h
new file mode 100644
index 0000000..d5ed546
--- /dev/null
+++ b/src/internal/toksvc_daemon_impl.h
@@ -0,0 +1,37 @@
+#ifndef TOKSVC_DAEMON_IMPL_H
+#define TOKSVC_DAEMON_IMPL_H
+
+#include <psxtypes/psxtypes.h>
+#include <ntapi/ntapi.h>
+
+enum toks_daemon_opcodes {
+	TOKS_DAEMON_OPCODE_BASE	= 0x20000,
+	TOKS_DAEMON_CONNECT	= TOKS_DAEMON_OPCODE_BASE,
+	TOKS_DAEMON_DISCONNECT,
+	TOKS_DAEMON_TTYSIGNAL,
+	TOKS_DAEMON_IPCSIGNAL,
+	TOKS_DAEMON_SIGCHLD,
+	TOKS_DAEMON_THREADEXIT,
+	TOKS_DAEMON_OPCODE_CAP
+};
+
+typedef int32_t __stdcall toks_daemon_routine(nt_tty_port_msg *);
+
+struct toks_daemon_ctx {
+	nt_port_keys		daemon_keys;
+	nt_port_attr		daemon_attr;
+	nt_port_name		daemon_name;
+
+	void *			hport_daemon;
+	void *			hevent_daemon_ready;
+
+	void *			hport_internal_client;
+	void *			hevent_internal_client_ready;
+};
+
+int32_t __stdcall toks_daemon_init(struct toks_daemon_ctx *, uint64_t);
+int32_t __stdcall toks_daemon_loop(void *);
+int32_t __stdcall toks_daemon_connect(nt_tty_port_msg *);
+int32_t __stdcall toks_daemon_signal(nt_tty_port_msg *);
+
+#endif